HTG Iris API
The Iris API is the backend of the new ERP for HTG Express.
TL;DR
helm repo add htg https://charts.htg.example
helm install infra-iris-api htg/infra-iris-api
Introduction
This chart bootstraps a HTG Iris API deployment on a Kubernetes cluster using the Helm package manager.
Prerequisites
- Kubernetes 1.20+
- Helm 3.2.0+
- PV provisioner support in the underlying infrastructure
- KEDA 2.0+ (optional, for worker autoscaling)
Installing the chart
To install the chart with the release name infra-iris-api:
helm install infra-iris-api oci://registry-1.docker.io/htg/infra-iris-api
The command deploys HTG Iris API on the Kubernetes cluster in the default configuration. The Parameters section lists the parameters that can be configured during installation.
Tip: List all releases using helm list
Uninstalling the chart
To uninstall/delete the infra-iris-api deployment:
helm delete infra-iris-api
The command removes all the Kubernetes components associated with the chart and deletes the release.
Parameters
Global parameters
| Name |
Description |
Value |
nameOverride |
String to partially override common.names.fullname |
"" |
fullnameOverride |
String to fully override common.names.fullname |
"" |
Common parameters
| Name |
Description |
Value |
replicaCount |
Number of container replicas |
1 |
strategy |
Pods replacement strategy type |
{} |
podLabels |
Extra labels for pods |
{} |
podAnnotations |
Annotations for pods |
{} |
podSecurityContext |
Security context for pods |
{} |
imagePullSecrets |
Image pull secrets for the application container |
[] |
Application image parameters
| Name |
Description |
Value |
image.repository |
Application image repository |
"" |
image.tag |
Application image tag |
"" |
image.pullPolicy |
Image pull policy |
"IfNotPresent" |
ECR configuration parameters
| Name |
Description |
Value |
ecr.enabled |
Enable ECR integration |
false |
ecr.serviceAccount.annotations |
ECR ServiceAccount annotations |
{} |
Application configuration parameters
| Name |
Description |
Value |
configuration.additionalConfigMaps |
Dynamic ConfigMaps generation configuration |
{} |
configuration.php |
PHP custom configuration |
{} |
configuration.phpFpm.maxChildren |
Number of child processes in static pool |
"1" |
configuration.phpFpm.maxRequests |
Number of requests per child before respawning |
"500" |
configuration.phpFpm.port |
Port to listen on for PHP-FPM |
9000 |
Container ports parameters
| Name |
Description |
Value |
containerPorts |
List of container ports to enable |
[{"name": "php-fpm", "containerPort": 9000, "protocol": "TCP"}] |
Probes parameters
| Name |
Description |
Value |
readinessProbe.enabled |
Enable readiness probe |
"true" |
readinessProbe.failureThreshold |
Failure threshold for readiness probe |
"5" |
readinessProbe.initialDelaySeconds |
Initial delay for readiness probe |
"10" |
readinessProbe.periodSeconds |
Period for readiness probe |
"10" |
readinessProbe.port |
Port for readiness probe |
"9000" |
readinessProbe.successThreshold |
Success threshold for readiness probe |
"1" |
readinessProbe.timeoutSeconds |
Timeout for readiness probe |
"1" |
livenessProbe.enabled |
Enable liveness probe |
"true" |
livenessProbe.failureThreshold |
Failure threshold for liveness probe |
"5" |
livenessProbe.initialDelaySeconds |
Initial delay for liveness probe |
"10" |
livenessProbe.periodSeconds |
Period for liveness probe |
"10" |
livenessProbe.port |
Port for liveness probe |
"9000" |
livenessProbe.successThreshold |
Success threshold for liveness probe |
"1" |
livenessProbe.timeoutSeconds |
Timeout for liveness probe |
"1" |
customLivenessProbe |
Custom liveness probe configuration |
{} |
customReadinessProbe |
Custom readiness probe configuration |
{} |
Resources parameters
| Name |
Description |
Value |
resources |
Resource requests and limits for application |
{} |
securityContext |
Security context for application container |
{} |
extraVolumeMounts |
Extra volume mounts for application container |
[] |
NGINX parameters
| Name |
Description |
Value |
nginx.image.repository |
NGINX image repository |
"nginx" |
nginx.image.tag |
NGINX image tag |
"stable" |
nginx.image.pullPolicy |
NGINX image pull policy |
"IfNotPresent" |
nginx.resources |
Resource requests and limits for NGINX |
{} |
nginx.securityContext |
Security context for NGINX container |
{} |
nginx.extraVolumeMounts |
Extra volume mounts for NGINX container |
[] |
PHP-FPM exporter parameters
| Name |
Description |
Value |
phpFpmExporter.enabled |
Enable PHP-FPM metrics exporter |
"true" |
phpFpmExporter.image.repository |
PHP-FPM Exporter image repository |
"hipages/php-fpm_exporter" |
phpFpmExporter.image.tag |
PHP-FPM Exporter image tag |
"v2.2" |
phpFpmExporter.image.pullPolicy |
PHP-FPM Exporter image pull policy |
"IfNotPresent" |
phpFpmExporter.resources |
Resource requests and limits for PHP-FPM exporter |
{} |
phpFpmExporter.securityContext |
Security context for PHP-FPM exporter |
{} |
Volume parameters
| Name |
Description |
Value |
extraVolumes |
Extra volumes for pods |
[] |
Scheduling parameters
| Name |
Description |
Value |
affinity |
Affinity for pod assignment |
{} |
nodeSelector |
Node labels for pod assignment |
{} |
tolerations |
Tolerations for pod assignment |
[] |
ServiceAccount parameters
| Name |
Description |
Value |
serviceAccount.create |
Create ServiceAccount |
true |
serviceAccount.automount |
Automount ServiceAccount token |
true |
serviceAccount.annotations |
ServiceAccount annotations |
{} |
serviceAccount.name |
ServiceAccount name |
"" |
Service parameters
| Name |
Description |
Value |
service.type |
Service type |
ClusterIP |
service.port |
Service port |
80 |
Autoscaling parameters
| Name |
Description |
Value |
autoscaling.enabled |
Enable autoscaling |
"false" |
autoscaling.minReplicas |
Minimum number of replicas |
"1" |
autoscaling.maxReplicas |
Maximum number of replicas |
"10" |
autoscaling.targets.cpu |
CPU target for autoscaling |
"" |
autoscaling.targets.phpFpmProcessUtilization |
PHP-FPM process utilization target |
"" |
Ingress parameters
| Name |
Description |
Value |
ingress.enabled |
Enable ingress |
false |
ingress.className |
Ingress class name |
"" |
ingress.annotations |
Ingress annotations |
{} |
ingress.hosts |
Ingress hosts configuration |
[{"host": "chart-example.local", "paths": [{"path": "/", "pathType": "ImplementationSpecific"}]}] |
ingress.tls |
Ingress TLS configuration |
[] |
External secrets parameters
| Name |
Description |
Value |
externalSecrets.secretStores |
SecretStore or ClusterSecretStore definitions |
[] |
externalSecrets.secrets |
ExternalSecrets configuration |
[] |
Storage parameters
| Name |
Description |
Value |
storage.storageClasses |
List of StorageClass definitions to create |
[] |
storage.persistentVolumeClaims |
List of PVC definitions to create |
[] |
Jobs parameters
| Name |
Description |
Value |
jobs |
List of jobs to create |
[] |
Workers parameters
| Name |
Description |
Value |
workers |
List of worker deployments to create |
[] |
Worker autoscaling parameters (per worker)
| Name |
Description |
Value |
workers[].autoscaling.enabled |
Enable KEDA autoscaling for this worker |
false |
workers[].autoscaling.minReplicaCount |
Minimum replicas (0 allows scale-to-zero) |
0 |
workers[].autoscaling.maxReplicaCount |
Maximum replicas |
10 |
workers[].autoscaling.pollingInterval |
Seconds between Redis queue checks |
30 |
workers[].autoscaling.cooldownPeriod |
Seconds to wait before scaling down |
300 |
workers[].autoscaling.trigger.address |
Redis server address (host:port) |
"" |
workers[].autoscaling.trigger.databaseIndex |
Redis database index |
"0" |
workers[].autoscaling.trigger.listName |
Redis list/queue name to monitor |
"" |
workers[].autoscaling.trigger.listLength |
Message threshold to trigger scaling |
"5" |
workers[].autoscaling.trigger.auth.secretName |
K8s secret with Redis credentials (optional) |
"" |
workers[].autoscaling.trigger.auth.passwordKey |
Key in secret containing password |
"REDIS_PASSWORD" |
Configuration and installation details
External secrets configuration
This chart supports integration with External Secrets Operator for managing secrets from external secret stores like AWS Secrets Manager, HashiCorp Vault, etc.
Example AWS Secrets Manager configuration:
externalSecrets:
secretStores:
- name: "aws-secrets-manager-store"
provider:
aws:
service: "SecretsManager"
region: "us-east-1"
auth:
jwt:
serviceAccountRef:
name: "my-app-sa"
secrets:
- name: "app-secrets"
secretStoreRef:
name: "aws-secrets-manager-store"
data:
- secretKey: "DATABASE_PASSWORD"
remoteRef:
key: "prod/app/database"
property: "password"
Storage configuration
PersistentVolumeClaim creation
Create PVCs dynamically for your application storage needs:
storage:
persistentVolumeClaims:
- name: "uploads"
spec:
accessModes:
- "ReadWriteMany"
storageClassName: "efs-shared"
resources:
requests:
storage: "10Gi"
Jobs configuration
Create Kubernetes Jobs for tasks like database migrations:
jobs:
- name: "migrations"
enabled: true
command: ["bash", "-c"]
args:
- |
php artisan migrate --force
activeDeadlineSeconds: 300
backoffLimit: 3
annotations:
"argocd.argoproj.io/hook": "PreSync"
"argocd.argoproj.io/hook-delete-policy": "HookSucceeded"
Workers configuration
Create Laravel queue workers as separate deployments for processing background jobs:
workers:
- name: "default-worker"
enabled: true
replicaCount: 2
command: ["php"]
args:
- |
artisan queue:work --sleep=3 --tries=3 --max-time=3600 --memory=512
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
env:
- name: "QUEUE_CONNECTION"
value: "redis"
Workers autoscaling with KEDA
Enable event-driven autoscaling for workers based on queue length using KEDA.
Prerequisites: KEDA must be installed in the cluster before enabling worker autoscaling.
Basic autoscaling configuration:
workers:
- name: "default"
enabled: true
command: ["php"]
args:
- artisan queue:work --queue=default --sleep=3 --tries=3
resources:
requests:
cpu: "100m"
memory: "128Mi"
autoscaling:
enabled: true
minReplicaCount: 1 # Keep at least 1 replica running
maxReplicaCount: 10
pollingInterval: 15 # Check queue every 15 seconds
cooldownPeriod: 180 # Wait 3 minutes before scaling down
trigger:
address: "redis:6379"
databaseIndex: "0"
listName: "queues:default"
listLength: "10" # Scale up when queue has more than 10 messages
auth:
secretName: "app-secrets"
passwordKey: "REDIS_PASSWORD"
Scale to zero configuration:
workers:
- name: "notifications"
enabled: true
command: ["php"]
args:
- artisan queue:work --queue=notifications
autoscaling:
enabled: true
minReplicaCount: 0 # Scale to zero when queue is empty
maxReplicaCount: 5
pollingInterval: 30
cooldownPeriod: 300
trigger:
address: "redis:6379"
listName: "queues:notifications"
listLength: "5"
auth:
secretName: "app-secrets"
passwordKey: "REDIS_PASSWORD"
Note: With minReplicaCount: 0, the first message may take up to pollingInterval seconds to be processed while KEDA scales up the first pod.
Redis without authentication:
workers:
- name: "default"
enabled: true
command: ["php"]
args:
- artisan queue:work --queue=default
autoscaling:
enabled: true
minReplicaCount: 1
maxReplicaCount: 10
trigger:
address: "redis:6379"
databaseIndex: "2"
listName: "queues:default"
listLength: "10"
# No auth section needed for Redis without password
Multiple workers with different Redis instances:
Each worker can connect to a different Redis instance or database:
workers:
- name: "emails"
enabled: true
command: ["php"]
args:
- artisan queue:work --queue=emails
autoscaling:
enabled: true
minReplicaCount: 1
maxReplicaCount: 20
trigger:
address: "redis-primary:6379"
databaseIndex: "0"
listName: "queues:emails"
listLength: "10"
auth:
secretName: "redis-primary-secret"
passwordKey: "REDIS_PASSWORD"
- name: "external-api"
enabled: true
command: ["php"]
args:
- artisan queue:work --queue=external
autoscaling:
enabled: true
minReplicaCount: 0
maxReplicaCount: 5
trigger:
address: "redis-secondary:6379"
databaseIndex: "2"
listName: "queues:external"
listLength: "5"
auth:
secretName: "redis-secondary-secret"
passwordKey: "PASSWORD"
Configuration management
Additional configmaps
Create custom ConfigMaps for your application:
configuration:
additionalConfigMaps:
app:
APP_NAME: "htg-iris"
APP_ENV: "production"
cache:
REDIS_HOST: "redis.example.com"
REDIS_PORT: "6379"
PHP configuration
Customize PHP settings:
configuration:
php:
date.timezone: "Europe/Madrid"
memory_limit: "1024M"
post_max_size: "100M"
opcache.max_accelerated_files: "60000"
PHP-FPM configuration
Tune PHP-FPM settings:
configuration:
phpFpm:
maxChildren: "10"
maxRequests: "1000"
port: 9000
Autoscaling
CPU-based autoscaling
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 20
targets:
cpu: 70
PHP-FPM process utilization autoscaling
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 20
targets:
phpFpmProcessUtilization: 80