Bahriya Tersane

Documentation / safeena

Safeena

A Helm chart for deploying HTTP services on Kubernetes behind the Kong ingress controller. Safeena (Arabic for “ship”) handles ingress, TLS certificates, Kong plugins, autoscaling, and health probes out of the box.

The chart requires the Kong ingress controller (IngressClass kong), which the Bahriya Kubernetes Engine installs. cert-manager is required only when the certificates list is used, and then with a ClusterIssuer of your choosing.

The chart’s App Version does not change, because the chart deploys whatever application image it is given rather than one particular application.

Prerequisites

  • Kubernetes 1.23+
  • Helm 3.x
  • Kong Ingress Controller (IngressClass kong)
  • cert-manager and a ClusterIssuer, if the certificates list is used
  • Valkey / Redis instance for rate limiting (if rate limiting is enabled)

Architecture

                     ┌──────────────────┐
Internet ──────────► │  Kong Ingress    │
                     │  (HTTPS, plugins)│
                     └────────┬─────────┘
                              │
                     ┌────────▼─────────┐
                     │  Service (ClusterIP) │
                     └────────┬─────────┘
                              │
              ┌───────────────┼───────────────┐
              │               │               │
         ┌────▼───┐     ┌────▼───┐     ┌────▼───┐
         │ Pod 0  │     │ Pod 1  │     │ Pod 2  │    (HPA-managed replicas)
         └────────┘     └────────┘     └────────┘
  • Kong terminates TLS and enforces HTTPS with 301 redirects.
  • Pods are spread across nodes via topologySpreadConstraints (built-in, maxSkew: 1, ScheduleAnyway).
  • HPA scales based on CPU utilisation (enabled by default, target 100%).
  • Optional Kong plugins: basic auth, rate limiting, IP restriction (whitelist/blacklist).
  • Optional www-to-root domain redirection via Kong redirect plugin.

Installation

# Basic deployment
helm install my-api charts/safeena \
  --set image.repository=my-registry/my-api \
  --set image.tag=v1.0.0

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

# With autoscaling tuning
helm install my-api charts/safeena \
  --set image.repository=my-registry/my-api \
  --set autoscaling.minReplicas=2 \
  --set autoscaling.maxReplicas=10 \
  --set autoscaling.targetCPUUtilizationPercentage=70

Configuration

Ingress, hostnames, and TLS

Ingress is enabled by default with Kong as the ingress class. HTTPS is enforced via Kong annotations that redirect HTTP to HTTPS with a 301 status code.

Each hostname is an entry in ingress.hosts, and each TLS secret an entry in ingress.tls. Certificates are issued by explicit cert-manager Certificate resources, listed in certificates, rather than by ingress annotations. Each names a ClusterIssuer in your cluster, so hostnames in different DNS zones can use different issuers. A www. variant can be redirected to its apex through a per-host redirect Service.

ingress:
  enabled: true
  forceHttps: true
  className: "kong"
  hosts:
    - host: example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www: { enabled: false }
    - host: www.example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www:
              enabled: true
              serviceName: redirect-www-my-api-example-com
  tls:
    - secretName: my-api-tls
      hosts:
        - example.com
        - www.example.com

certificates:
  - secretName: my-api-tls
    issuer: letsencrypt-prod      # any ClusterIssuer in your cluster
    dnsNames:
      - example.com
      - www.example.com

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 container:

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

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

Health probes

Two probes are configured by default:

  • Startup probe: HTTP GET to / on port http, every 10 seconds, 6 failures allowed (60s total bootstrap time).
  • Liveness probe: HTTP GET to / on port http after startup succeeds.

Override the probe paths for APIs with custom health endpoints:

startupProbe:
  httpGet:
    path: /healthz
    port: http
  periodSeconds: 10
  failureThreshold: 6

livenessProbe:
  httpGet:
    path: /healthz
    port: http

Autoscaling

Horizontal Pod Autoscaler is enabled by default targeting 100% CPU utilisation:

autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 3
  targetCPUUtilizationPercentage: 100
  # targetMemoryUtilizationPercentage: 80

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

WWW → apex redirection

redirect.www is a list — one entry per apex hostname that opted into a www. → apex redirect. Each entry renders:

  1. A dedicated Service (name: from the entry) annotated with konghq.com/plugins: <name>.
  2. A KongPlugin (also named <name>) of plugin: redirect, with keep_incoming_path: true so the path and query string are preserved.
  3. A matching ingress.hosts entry for www.<apex> whose paths[].redirect.www.serviceName points at that Service.
redirect:
  www:
    - name: redirect-www-my-site-example-com
      url: https://example.com
    - name: redirect-www-my-site-customer-org
      url: https://customer.org

ingress:
  hosts:
    - host: example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www: { enabled: false }
    - host: www.example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www:
              enabled: true
              serviceName: redirect-www-my-site-example-com
    - host: customer.org
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www: { enabled: false }
    - host: www.customer.org
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www:
              enabled: true
              serviceName: redirect-www-my-site-customer-org

The www.<apex> host must appear in ingress.tls and certificates alongside its apex. The chart does not derive the redirect Service’s name: choose one, and use the same value in redirect.www[].name and in ingress.hosts[].paths[].redirect.www.serviceName. Each apex has its own Service and KongPlugin, so each can redirect to its own canonical URL.

Kong plugins

Basic authentication

kong:
  basicAuth:
    enabled: true
    hideCredentials: true
    credentials:
      - username: admin
        password: s3cret

When enabled, creates a KongPlugin (basic-auth), KongConsumer, and credential Secret for each entry. The plugin is automatically added to the ingress annotations.

Rate limiting

kong:
  rateLimiting:
    enabled: true
    requestsPerMinute: 60
    requestsPerHour: 1000

Uses Kong’s rate-limiting plugin backed by Valkey/Redis (valkey-ratelimiting-primary:6379). The plugin is fault-tolerant — if Redis is unavailable, requests are allowed through.

IP restriction

Whitelist or blacklist IP addresses:

kong:
  ipRestriction:
    whitelist:
      enabled: true
      ips:
        - 203.0.113.0/24
        - 198.51.100.10
    blacklist:
      enabled: false
      ips: []

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. Containers deployed via Safeena can mount this ConfigMap to verify the MySQL server’s identity and establish encrypted connections.

Safeena values configuration

Use volumes, volumeMounts, and env in your Safeena values to wire the CA certificate into your application:

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 application then reads the MYSQL_SSL_CA environment variable and passes it to its MySQL driver as the CA certificate path. See the MySQL chart README for driver-specific examples (PHP/Kipchak, Node.js, Python, Go, CLI).

Examples

Kipchak API with autoscaling

fullnameOverride: "my-api"
image:
  repository: registry.example.com/acme/my-api
  tag: "v2.1.0"
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 256Mi
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 8
  targetCPUUtilizationPercentage: 70
env:
  - name: APP_ENV
    value: production
envFrom:
  - secretRef:
      name: my-api-env
certificates:
  - secretName: my-api-tls
    issuer: letsencrypt-prod
    dnsNames:
      - api.example.com
ingress:
  hosts:
    - host: api.example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www:
              enabled: false
  tls:
    - secretName: my-api-tls
      hosts:
        - api.example.com

Website with a www-redirect

fullnameOverride: "my-website"
image:
  repository: registry.example.com/acme/my-website
  tag: "v1.0.0"

redirect:
  www:
    - name: redirect-www-my-website-example-com
      url: https://example.com

certificates:
  - secretName: my-website-tls
    issuer: letsencrypt-prod
    dnsNames:
      - example.com
      - www.example.com

ingress:
  hosts:
    - host: example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www: { enabled: false }
    - host: www.example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
          redirect:
            www:
              enabled: true
              serviceName: redirect-www-my-website-example-com
  tls:
    - secretName: my-website-tls
      hosts:
        - example.com
        - www.example.com

API with rate limiting and IP whitelist

fullnameOverride: "admin-api"
image:
  repository: registry.example.com/acme/admin-api
  tag: "v3.0.0"
resources:
  limits:
    cpu: "1"
    memory: 1Gi
  requests:
    cpu: 250m
    memory: 512Mi
kong:
  rateLimiting:
    enabled: true
    requestsPerMinute: 30
    requestsPerHour: 500
  ipRestriction:
    whitelist:
      enabled: true
      ips:
        - 203.0.113.0/24
        - 198.51.100.10
env:
  - name: APP_ENV
    value: production
envFrom:
  - secretRef:
      name: admin-api-env

API with MySQL TLS

fullnameOverride: "billing-api"
image:
  repository: registry.example.com/acme/billing-api
  tag: "v1.2.0"
volumes:
  - name: mysql-ca
    configMap:
      name: billing-db-tls-ca
volumeMounts:
  - name: mysql-ca
    mountPath: /etc/mysql-tls
    readOnly: true
env:
  - name: APP_ENV
    value: production
  - name: MYSQL_SSL_CA
    value: /etc/mysql-tls/ca.crt
envFrom:
  - secretRef:
      name: billing-api-env

Parameters

Image

Parameter Description Default
image.repository Container image repository nginx
image.tag Container image tag 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.type Service type ClusterIP
service.port Service port 80

Ingress

Parameter Description Default
ingress.enabled Enable Ingress resource true
ingress.forceHttps Force HTTPS via Kong 301 redirect true
ingress.className Ingress class name "kong"
ingress.annotations Additional ingress annotations {}
ingress.hosts List of {host, paths} entries See values.yaml
ingress.hosts[].paths[].path URL path /
ingress.hosts[].paths[].pathType K8s path type ImplementationSpecific
ingress.hosts[].paths[].redirect.www.enabled Route this host to a www-redirect Service false
ingress.hosts[].paths[].redirect.www.serviceName Name of the redirect Service to back this host (must match an entry in redirect.www[].name) —
ingress.tls List of {secretName, hosts} TLS bindings See values.yaml

Certificates

Parameter Description Default
certificates List of cert-manager Certificate resources []
certificates[].secretName Name of the TLS Secret to create —
certificates[].issuer ClusterIssuer name (see issuer table above) —
certificates[].dnsNames List of DNS names for the certificate —

Health probes

Parameter Description Default
startupProbe.httpGet.path Startup probe HTTP path /
startupProbe.httpGet.port Startup probe port http
startupProbe.periodSeconds Startup probe interval 10
startupProbe.failureThreshold Startup probe max failures 6
livenessProbe.httpGet.path Liveness probe HTTP path /
livenessProbe.httpGet.port Liveness probe port http

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 true
autoscaling.minReplicas Minimum replicas 1
autoscaling.maxReplicas Maximum replicas 3
autoscaling.targetCPUUtilizationPercentage CPU target for scaling 100
autoscaling.targetMemoryUtilizationPercentage Memory target for scaling (optional) —

WWW redirect

redirect.www is a list — one entry per apex hostname that opts in. Each entry renders a Service + KongPlugin pair, addressed by name. The matching ingress.hosts[].paths[].redirect.www.serviceName must equal redirect.www[].name.

Parameter Description Default
redirect.www List of {name, url} redirect entries []
redirect.www[].name Service / KongPlugin name. Conventionally redirect-www-<container-handle>-<apex-with-dashes>. —
redirect.www[].url Target URL the www. host redirects to (must include scheme). The Kong plugin appends the incoming path and query. —

Kong plugins

Parameter Description Default
kong.basicAuth.enabled Enable basic authentication false
kong.basicAuth.hideCredentials Strip credentials from upstream request true
kong.basicAuth.credentials List of {username, password} entries []
kong.rateLimiting.enabled Enable rate limiting false
kong.rateLimiting.requestsPerMinute Requests per minute limit null
kong.rateLimiting.requestsPerHour Requests per hour limit null
kong.ipRestriction.whitelist.enabled Enable IP whitelist false
kong.ipRestriction.whitelist.ips Allowed IP addresses/CIDRs []
kong.ipRestriction.blacklist.enabled Enable IP blacklist false
kong.ipRestriction.blacklist.ips Denied IP addresses/CIDRs []

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 {}