Bahriya Tersane

Documentation / khadim

Khadim

A lean Helm chart for deploying worker and daemon containers on Kubernetes. Khadim (Arabic for “servant”) is designed for non-HTTP workloads: queue workers, background processors, cron consumers, and long-running daemons.

Unlike Safeena (which includes ingress, Kong plugins, and TLS certificates), Khadim has no networking by default — no Ingress, no Kong, no cert-manager. It deploys a Deployment with optional Service, HPA, and health probes.

Prerequisites

  • Kubernetes 1.23+
  • Helm 3.x

Architecture

┌─────────────────────────────────┐
│         Deployment              │
│  ┌───────────┐ ┌───────────┐   │
│  │  worker-0  │ │  worker-1  │  │    (replicas controlled by replicaCount or HPA)
│  └───────────┘ └───────────┘   │
└─────────────────────────────────┘
         │ (optional)
    ┌────▼────┐
    │ Service │   (only when service.enabled = true, e.g., for health check endpoints)
    └─────────┘
  • Each pod runs your worker image as PID 1.
  • No ingress or external access by default.
  • Pods are spread across nodes via topologySpreadConstraints (built-in, maxSkew: 1, ScheduleAnyway).
  • Optional Service for exposing a health check port (e.g., for liveness probes or internal monitoring).

Installation

# Basic worker
helm install my-worker charts/khadim \
  --set image.repository=my-registry/my-worker \
  --set image.tag=latest

# With a fixed resource name, independent of the release name
helm install my-worker charts/khadim \
  --set fullnameOverride=my-worker \
  --set image.repository=my-registry/my-worker \
  --set image.tag=v1.2.3

# With multiple replicas and autoscaling
helm install my-worker charts/khadim \
  --set image.repository=my-registry/my-worker \
  --set autoscaling.enabled=true \
  --set autoscaling.minReplicas=2 \
  --set autoscaling.maxReplicas=10 \
  --set autoscaling.targetCPUUtilizationPercentage=70

Configuration

Environment variables

Inject environment variables directly or from Kubernetes Secrets/ConfigMaps:

env:
  - name: APP_ENV
    value: production
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: my-db-credentials
        key: password

envFrom:
  - secretRef:
      name: my-app-secrets
  - configMapRef:
      name: my-app-config

Volumes and volume mounts

Mount ConfigMaps, Secrets, PVCs, or emptyDirs into the worker container:

volumes:
  - name: config
    configMap:
      name: my-worker-config
  - name: tmp
    emptyDir: {}

volumeMounts:
  - name: config
    mountPath: /etc/my-worker
    readOnly: true
  - name: tmp
    mountPath: /tmp

Health probes

Probes are disabled by default since many workers don’t expose HTTP endpoints. Enable them when your worker has a health check:

service:
  enabled: true
  port: 8080

probes:
  enabled: true
  path: /healthz
  port: http
  bootstraptime: 30    # seconds to wait before failing startup probe

When probes are enabled:

  • A startup probe polls the health endpoint every 10 seconds, allowing up to bootstraptime / 10 failures before killing the pod.
  • A liveness probe continues checking after startup succeeds.
  • The Service must also be enabled to expose the health check port.

Autoscaling

Horizontal Pod Autoscaler based on CPU and/or memory utilisation:

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80    # optional

When autoscaling is enabled, the replicaCount value is ignored — the HPA manages replica count.

Pod topology spread

Khadim includes a built-in topologySpreadConstraints rule that spreads pods across nodes (maxSkew: 1, ScheduleAnyway). This is not configurable — it’s always applied to avoid hotspotting worker pods on a single node.

Connecting to MySQL with TLS

When a MySQL instance deployed with the mysql chart has TLS enabled, the MySQL chart publishes the CA certificate as a ConfigMap named <mysql-release>-tls-ca. Workers deployed via Khadim can mount this ConfigMap to verify the MySQL server’s identity and establish encrypted connections.

volumes:
  - name: mysql-ca
    configMap:
      name: my-db-tls-ca          # <mysql-release>-tls-ca

volumeMounts:
  - name: mysql-ca
    mountPath: /etc/mysql-tls
    readOnly: true

env:
  - name: MYSQL_SSL_CA
    value: /etc/mysql-tls/ca.crt

The worker then reads the MYSQL_SSL_CA environment variable and passes it to its MySQL driver. See the MySQL chart README for driver-specific examples (PHP/Kipchak, Node.js, Python, Go).

Examples

Queue worker

fullnameOverride: "billing-worker"
image:
  repository: registry.example.com/acme/queue-workers
  tag: "v1.5.0"
replicaCount: 2
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 256Mi
env:
  - name: WORKER_QUEUE
    value: billing
envFrom:
  - secretRef:
      name: billing-worker-env

Worker with health check and autoscaling

fullnameOverride: "email-sender"
image:
  repository: my-registry/email-sender
  tag: "latest"
service:
  enabled: true
  port: 8080
probes:
  enabled: true
  path: /healthz
  port: http
  bootstraptime: 60
autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 5
  targetCPUUtilizationPercentage: 80
resources:
  limits:
    cpu: "1"
    memory: 1Gi
  requests:
    cpu: 250m
    memory: 512Mi

Worker with MySQL TLS and Secrets

fullnameOverride: "data-processor"
image:
  repository: my-registry/data-processor
  tag: "v2.0.0"
replicaCount: 3
env:
  - name: DB_HOST
    value: my-db
  - name: MYSQL_SSL_CA
    value: /etc/mysql-tls/ca.crt
envFrom:
  - secretRef:
      name: data-processor-env
volumes:
  - name: mysql-ca
    configMap:
      name: my-db-tls-ca
volumeMounts:
  - name: mysql-ca
    mountPath: /etc/mysql-tls
    readOnly: true
resources:
  limits:
    cpu: "2"
    memory: 2Gi
  requests:
    cpu: 500m
    memory: 1Gi

Parameters

Image

Parameter Description Default
image.repository Container image repository nginx
image.tag Container image tag (defaults to appVersion) Set in each release
image.pullPolicy Image pull policy IfNotPresent
imagePullSecrets Image pull secrets [{name: 1x-ax}]

Deployment

Parameter Description Default
replicaCount Number of replicas (ignored when autoscaling is enabled) 1
nameOverride Override the chart name ""
fullnameOverride Override the full release name ""
podAnnotations Additional pod annotations {}
podLabels Additional pod labels {}
podSecurityContext Pod-level security context {}
securityContext Container-level security context {}

Service

Parameter Description Default
service.enabled Create a ClusterIP Service false
service.type Service type ClusterIP
service.port Service port 8080

Probes

Parameter Description Default
probes.enabled Enable startup and liveness probes false
probes.path HTTP path for health checks /healthz
probes.port Port name for health checks http
probes.bootstraptime Seconds to wait for startup before failing 30

Resources

Parameter Description Default
resources.limits.cpu CPU limit 100m
resources.limits.memory Memory limit 256Mi
resources.requests.cpu CPU request 20m
resources.requests.memory Memory request 64Mi

Autoscaling

Parameter Description Default
autoscaling.enabled Enable HPA false
autoscaling.minReplicas Minimum replicas 1
autoscaling.maxReplicas Maximum replicas 3
autoscaling.targetCPUUtilizationPercentage CPU target for scaling 100
autoscaling.targetMemoryUtilizationPercentage Memory target for scaling (optional) —

Environment

Parameter Description Default
env Environment variables for the container []
envFrom Environment variable sources (Secrets, ConfigMaps) []
volumes Additional volumes []
volumeMounts Additional volume mounts []

Service account

Parameter Description Default
serviceAccount.create Create a ServiceAccount false
serviceAccount.automount Auto-mount API credentials true
serviceAccount.annotations ServiceAccount annotations {}
serviceAccount.name ServiceAccount name (auto-generated if empty) ""

Scheduling

Parameter Description Default
nodeSelector Node selector labels {}
tolerations Pod tolerations []
affinity Pod affinity rules {}