Helm configuration
Annotations
Kubernetes annotations can be added to generated deployments by setting values in the annotations array property of the main configuration.
Note
Annotations keys will be prefixed by neos/, ex: my-key will be set to neos/my-key.
If you need to set a custom annotation on a specific deployment without the neos prefix, you can use annotations array property on report server, cluster backend, cluster task-runner or cluster frontend configuration.
Each value has the following properties :
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| key | Annotation key | string | true | |
| value | Annotation value | string | true |
Memory resources configuration
Most components support memory resources configuration via three properties:
memory: Sets both memory request and limit to the same value (legacy behavior)memoryRequest: Sets only the memory requestmemoryLimit: Sets only the memory limit
When memoryRequest and/or memoryLimit are configured, they take precedence over the memory property.
Update strategy configuration
Neos supports Kubernetes rollout strategy overrides for Deployments and StatefulSets.
Deployment strategy defaults
By default, all Neos Deployments use:
global:
deployment:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 50%
This default applies to both Development and Production presets unless a more specific strategy override is configured.
This default targets a practical balance between availability and resource usage during rollouts:
maxSurge: 1allows creating at most one extra pod above the desired replica count, which limits temporary overconsumption.maxUnavailable: 50%allows replacing part of the workload while keeping at least half of the desired pods available (rounded down for unavailable pods).
Quick rollout behavior examples:
- With
replicas: 1, Kubernetes creates 1 new pod first (maxSurge: 1), waits for it to become ready, then removes the old one. This keeps service availability during the update, with a short temporary peak at 2 pods. - With
replicas: 3, up to 1 pod can be unavailable at a time (50%of 3 rounds down to 1), and up to 1 extra pod can be added. In practice, the rollout progresses in small steps while keeping at least 2 ready pods and avoiding large resource spikes.
Deployment strategy override keys
- Global fallback:
global.deployment.strategy - Built-in services:
gateway.strategy,report.strategy,notificationsHub.strategy,tenantManagement.strategy,licenseManagement.strategy,taskScheduler.strategy,neosAI.strategy,supportCenter.strategy - Built-in components:
*.backend.strategy,*.frontend.strategy,*.taskRunner.strategy - Cross-service components:
interClusterCommunication.rabbitmq.updateStrategy(renders to RabbitMQ StatefulSetspec.updateStrategy),interClusterCommunication.zipkin.strategy,observability.collector.strategy - Business clusters:
clusters[].strategy,clusters[].backend.strategy,clusters[].frontend.strategy,clusters[].backend.taskRunner.strategy - Business cluster versions:
clusters[].versions[].strategy,clusters[].versions[].backend.strategy,clusters[].versions[].frontend.strategy,clusters[].versions[].backend.taskRunner.strategy
Task runner precedence in multitenant business clusters is:
clusters[].versions[].backend.taskRunner.strategy > clusters[].versions[].backend.strategy > clusters[].versions[].strategy > clusters[].strategy > global.deployment.strategy
StatefulSet strategy
Statefulset strategies can be set using:
interClusterCommunication.rabbitmq.updateStrategyfor the RabbitMQ StatefulSet (spec.updateStrategy)redis.master.updateStrategyfor the main Redis statefulsetredisGateway.master.updateStrategyfor the Redis statefulset used by the gatewayredisActor.master.updateStrategyfor the Redis statefulset used for background tasksredisSignalR.master.updateStrategyfor the Redis statefulset used by SignalR (notifications)
Authentication
To provide authentication configuration to the gateway and to SignalR (notifications), you must set the name of the secret to use on the authenticationSecret property of the main configuration.
Please see this article.
Gateway
The gateway handles authentication and redirects traffic to the right services
Note
Gateway CORS is configured through gateway runtime settings provided by gateway.envSecret.
See Gateway CORS configuration.
The following properties can be set on the gateway property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| envSecret | Secret name for gateway env variables | string | false | |
| logLevel | Gateway log level | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| replicas | Desired number of instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| maxBodySize | Maximum body size (see Custom max body size) | Body size | false | 5m |
| readTimeout | Proxy response read timeout in seconds (see Custom timeouts) | string | false | 300 |
| image | Specific image to use (eg: with custom tenant selection or custom status code pages) | string | false | |
| tag | Tag of the specific image to use (eg: with custom tenant selection or custom status code pages) | string | false | |
| imagePullSecret | Secret name for docker registry authentication (eg: with custom tenant selection or custom status code pages) | string | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | global.deployment.strategy |
Cluster Prefix Configuration
Clusters can be accessed via path-based routing using the prefix property as an alternative to host-based routing. This allows multiple clusters to share the same host domain by using different URL paths.
Overview
The prefix property on a cluster configuration provides a URL path segment for accessing the cluster. For example:
- Without prefix:
https://example.com/ - With prefix
myapp:https://example.com/myapp/ - Multiple clusters on same host:
https://shared.example.com/app-a/andhttps://shared.example.com/app-b/
Common Cluster Properties
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| host | Domain for cluster access (from outside Kubernetes) | string | false | |
| prefix | URL path prefix for cluster access (path-based routing) | string | false | |
| name | Cluster name | string | true | |
| multitenancy | Enable multi-tenancy support | boolean | false | false |
| strategy | Kubernetes deployment strategy fallback for cluster deployments (spec.strategy) |
object | false | global.deployment.strategy |
Validation Rules
The following rules apply to host and prefix configuration:
| Scenario | host | prefix | Result | Access URL |
|---|---|---|---|---|
| Host-based routing | ✓ | (empty) | Valid | https://myhost.com/ |
| Prefixed routing | ✓ | ✓ | Valid | https://myhost.com/{prefix}/ |
| Prefix without host | (empty) | ✓ | Invalid configuration | Not supported |
| Nested cluster | N/A | ✓ (required) | Nested cluster must use a prefix under its host | https://host/{parentPrefix}/{nestedPrefix}/ |
Important
When prefix is set, host is also required, and the cluster is accessed through https://{host}/{prefix}/. A prefixed cluster is not exposed at the root of the host. For nested clusters, prefix is mandatory.
Format Constraints
The prefix value should follow URL conventions:
- Lowercase alphanumeric characters:
a-z,0-9 - Hyphens for word separation:
- - Examples:
myapp,tenant-management,api-v1 - Avoid uppercase, special characters, and spaces
Nested Cluster Prefix Composition
When nested clusters have prefixes and the parent cluster also has a prefix, the paths are composed as:
{parentClusterPrefix}/{nestedClusterPrefix}/
For example:
- Parent cluster
TechnicalDemoswith no prefix (uses host) - Nested cluster
Northwindwith prefixnorthwind - Access URL:
https://host.com/northwind/
Or if parent has prefix demos:
- Access URL:
https://gateway.com/demos/northwind/
Usage Examples
Example 1: Single Cluster with Prefix
clusters:
- name: MyCluster
host: app.example.com
prefix: myapp
databaseType: PostgreSQL
multitenancy: true
Access: https://app.example.com/myapp/
Example 2: Multiple Clusters on Shared Host with Different Prefixes
clusters:
- name: ApplicationA
host: shared.example.com
prefix: app-a
databaseType: PostgreSQL
- name: ApplicationB
host: shared.example.com
prefix: app-b
databaseType: PostgreSQL
Access:
- ApplicationA:
https://shared.example.com/app-a/ - ApplicationB:
https://shared.example.com/app-b/
Example 3: Nested Clusters with Path Prefix Composition
clusters:
- name: TechnicalDemos
host: nested.example.com
multitenancy: true
nestedClusters:
- name: Northwind
pathPrefix: northwind
# Access: https://nested.example.com/northwind/
- name: Components
pathPrefix: components
# Access: https://nested.example.com/components/
Example 4: Shared Host with Prefixed Clusters
clusters:
- name: App-A
host: gateway.example.com
prefix: app-a
# Access: https://gateway.example.com/app-a/
- name: App-B
host: gateway.example.com
prefix: app-b
# Access: https://gateway.example.com/app-b/
- name: App-C
host: gateway.example.com
prefix: app-c
# Access: https://gateway.example.com/app-c/
Host-based vs Prefix-based Routing
| Aspect | Host-based | Prefixed on host |
|---|---|---|
| Configuration simplicity | Simple | Simple |
| Multiple clusters per host | No (one per host) | Yes (different paths) |
| TLS certificate | Per host | Shared |
| DNS setup | Multiple DNS records | Single DNS record |
| URL appearance | host1.com/, host2.com/ |
shared.com/app1/, shared.com/app2/ |
| Root host access | Cluster available at / |
Cluster not available at / |
| Scaling | More infrastructure | Less infrastructure |
Report
The report server handles report generation.
Note
For detailed information about report persistence modes, their benefits, and how to choose the right one for your environment, see Report Persistence Modes.
The following properties can be set on the report property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Deploy the report server | boolean | false | true |
| envSecret | Secret name for report server env variables (eg: Reporting__StimulsoftLicenceKey) |
string | false | |
| logLevel | Report server log level | Log level | ||
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| replicas | Desired number of instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 1024Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| image | Specific image to use (eg: with custom report server) | string | false | |
| tag | Tag of the specific image to use (eg: with custom report server) | string | false | |
| imagePullSecret | Secret name for docker registry authentication (eg: with custom report server) | string | false | |
| annotations | Kubernetes pod annotations | Annotation array | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | global.deployment.strategy |
Reports persistence
Reports can be persisted using one of three modes. Choose the mode that best fits your production requirements and infrastructure:
Legacy mode (default)
When no persistence configuration is provided, reports are stored in the cluster database. This mode is the default but has important limitations:
- Size limit: Reports are limited to 4MB per file
- Database storage: Reports consume database storage and resources
- Recommended use: Development environments only
No configuration is needed for this mode.
S3 mode (recommended for production)
Note
This is the recommended persistence mode for production environments due to its superior performance-to-cost ratio.
Store reports in AWS S3 or S3-compatible storage (Hexanet, MinIO, DigitalOcean Spaces, etc.).
Configuration via Kubernetes Secret
Create a Kubernetes Secret containing the S3 configuration parameters:
kubectl create secret generic my-s3-config-secret \
--from-literal=AWS__BucketName=neos-neos-devtest-reports \
--from-literal=AWS__ServiceURL=https://s3.example.com \
--from-literal=AWS__Region=defaultRegion \
--from-literal=AWS__AccessKey=YOUR_ACCESS_KEY \
--from-literal=AWS__SecretKey=YOUR_SECRET_KEY
Then set the configurationSecret property in the Helm values to reference this secret:
report:
S3:
configurationSecret: my-s3-config-secret
Important
S3 mode is only intended for business cluster versions 3.2 and later. If you need to keep an older business cluster running in an environment where report.S3.configurationSecret is configured globally, set clusters[].reportLegacyMode: true (mono-tenant) or clusters[].versions[].reportLegacyMode: true (multi-tenant) so it stays on the legacy Pub/Sub payload flow instead of trying to use distributed S3 storage.
Example with global S3 persistence and mixed cluster compatibility:
report:
S3:
configurationSecret: my-s3-config-secret
clusters:
# Monotenant legacy cluster: legacy mode at cluster level
- name: Northwind
version: "3.1"
reportLegacyMode: true
backend:
image: harbor.hexanet.fr:8443/neos/northwind-backend
tag: "3.1"
envSecret: northwind-env
# Multitenant cluster: legacy mode at version level
- name: TechnicalDemos
multitenancy: true
versions:
- version: "3.1"
reportLegacyMode: true
backend:
image: harbor.hexanet.fr:8443/neos/technicaldemos-backend
tag: "3.1"
envSecret: technicaldemos-env
- version: "3.2"
backend:
image: harbor.hexanet.fr:8443/neos/technicaldemos-backend
tag: "3.2"
envSecret: technicaldemos-env
# Monotenant non-legacy cluster (3.2+): no reportLegacyMode
- name: Components
version: "3.2"
backend:
image: harbor.hexanet.fr:8443/neos/components-backend
tag: "3.2"
envSecret: components-env
S3 Configuration Parameters
The Kubernetes Secret must contain the following keys (all under AWS__ namespace for Dapr binding):
| Key | Description | Required | Example | Notes |
|---|---|---|---|---|
AWS__BucketName |
S3 bucket name. Presence of this key activates S3 mode. | YES | neos-neos-devtest-reports |
Without this, legacy database mode is used. |
AWS__ServiceURL |
S3 endpoint URL for S3-compatible providers (Hexanet, MinIO, etc.) | NO | https://s3.hexanet.fr |
For native AWS S3, omit this; AWS SDK uses region-based endpoints. |
AWS__Region |
AWS region name (for native AWS S3 only; ignored if ServiceURL is set) | NO | us-east-1, eu-west-1 |
Required for native AWS S3. Ignored when ServiceURL is configured. |
AWS__AccessKey |
IAM access key ID | NO* | AKIAIOSFODNN7EXAMPLE |
Required if not using IAM roles. Ignored if using credential provider chain. |
AWS__SecretKey |
IAM secret access key | NO* | wJalrXUtnFEMI/K7MDENG... |
Must be paired with AccessKey. |
AWS__SessionToken |
Temporary session token (for STS credentials) | NO | AQoDYXdzEJr.. |
Optional; used only with temporary credentials. |
Important
Critical for S3-compatible endpoints (Hexanet, MinIO, DigitalOcean): When AWS__ServiceURL is configured, the SDK automatically enables path-style addressing internally. This is required because most S3-compatible providers do not support virtual-hosted-style URLs (e.g., {bucket}.s3.hexanet.fr).
Helm Values Examples
AWS S3 Native (IAM Role)
report:
S3:
configurationSecret: aws-s3-native-iam-role
# Secret contains only:
# - AWS__BucketName: my-reports-bucket
# - AWS__Region: eu-west-1
# Access key/secret omitted; pod IAM role provides credentials
S3-Compatible Endpoint (Hexanet)
report:
S3:
configurationSecret: hexanet-s3-config
# Secret contains:
# - AWS__BucketName: neos-neos-devtest-reports
# - AWS__ServiceURL: https://s3.hexanet.fr
# - AWS__Region: defaultRegion (optional, for clarity)
# - AWS__AccessKey: explicit static credentials
# - AWS__SecretKey: explicit static credentials
Multi-Region with Per-Region Buckets
report:
S3:
configurationSecret: s3-multi-region
# Secret contains:
# - AWS__BucketName: neos-reports-eu
# - AWS__Region: eu-west-1
# - AWS__AccessKey: multi-account IAM user
# - AWS__SecretKey: multi-account IAM secret
Troubleshooting S3 Connectivity
If you encounter Name does not resolve errors in report server logs (e.g., Name does not resolve (neos-neos-devtest-reports.s3.hexanet.fr:443)), verify the following:
1. Verify the endpoint is reachable using kubectl debug:
Since the report server pod is hardened (no curl/nslookup), use kubectl debug to spawn a temporary debug pod:
kubectl debug -it -n <namespace> pod/neos-report-server-xxx --image=nicolaka/netshoot:latest -- bash
# Inside debug container:
curl -v https://s3.hexanet.fr/
2. Check DNS resolution using kubectl debug:
kubectl debug -it -n <namespace> pod/neos-report-server-xxx --image=nicolaka/netshoot:latest -- bash
# Inside debug container:
nslookup s3.hexanet.fr
# Or use getent:
getent hosts s3.hexanet.fr
3. Check pod events and logs:
# View pod events for connection errors
kubectl describe pod -n <namespace> neos-report-server-xxx | grep -A 20 Events
# View pod logs for S3 initialization errors
kubectl logs -n <namespace> neos-report-server-xxx | grep -i s3
4. Verify Secret contents:
kubectl get secret my-s3-config-secret -o yaml
5. Enable debug logging:
report:
logLevel: Debug # Logs S3 client initialization details
6. Common issues:
- Missing
AWS__ServiceURLfor S3-compatible endpoints → SDK uses virtual-hosted style (fails) - Wrong S3 endpoint URL → Network connectivity issue
- Expired or missing credentials → Authentication failure
- Network policy restrictions → Pod cannot reach external endpoint
Volume mode (filesystem)
Store reports on a persistent volume attached to the reporting server file system at /var/lib/neos/reports/.
Configure by setting the volume property:
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| storageClassName | Name of the Kubernetes storage class to use | string | true | |
| pvcName | Name of the persistent volume claim resource to use. Will be created if it does not exist. | string | true | |
| size | Volume size | Memory resource units | false | 1Gi |
| accessMode | Volume access mode | Volume access modes | false | ReadWriteMany |
report:
volume:
storageClassName: my-storage-class
pvcName: neos-reports-pvc
size: 10Gi
accessMode: ReadWriteMany
Tenant Management
Tenant Management cluster allows to manage multiple tenants in Neos clusters.
Note
Tenant Management configuration is only mandatory if your clusters run in multi tenancy mode.
Common
The following properties can be set on the tenantManagement property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| databaseType | Database persistence type (Oracle, PostgreSQL or SqlServer) | string | true | |
| host | Domain for Tenant Management access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| envSecret | Secret name for backend tenantManagement container env variables (at least PersistenceSettings__ConnectionString) | string | false | |
| jsonConfigurationSecret | Secret name for tenantManagement frontend container additional configuration (like ApplicationInsights) | string | false | |
| defaultUserAccountLogin | The identifier of the user to create when starting the Tenant Management cluster on an empty database. The user account should already exist in authentication provider. | string | false | |
| logLevel | Log level for Tenant Management containers | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| clusterResiliencyPolicies | Cluster resiliency policies | Cluster resiliency policies | false | |
| strategy | Kubernetes deployment strategy fallback (spec.strategy) |
object | false | global.deployment.strategy |
Backend
The following properties can be set on the backend property of the Tenant Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 1024Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | tenantManagement.strategy |
TaskRunner
The following properties can be set on the taskRunner property of the Tenant Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of task runner instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 1024Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | tenantManagement.strategy |
Frontend
The following properties can be set on the frontend property of the Tenant Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of frontend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 64Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | tenantManagement.strategy |
API Documentation (Swagger)
By default, the API documentation UI (Swagger) is not exposed.
You can configure it by setting the following properties on the apiDocumentation property of the Tenant Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable API documentation interface | boolean | false | false |
| prefix | Prefix for API documentation access (eg: https://<host>/<prefix>/) |
string | false | api-documentation |
License Management
License Management cluster allows to manage licenses in Neos clusters.
Note
License Management configuration is only mandatory if you need to manage licenses.
Common
The following properties can be set on the licenseManagement property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| databaseType | Database persistence type (Oracle, PostgreSQL or SqlServer) | string | true | |
| host | Domain for License Management access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| envSecret | Secret name for backend licenseManagement container env variables (at least PersistenceSettings__ConnectionString) | string | false | |
| jsonConfigurationSecret | Secret name for licenseManagement frontend container additional configuration (like ApplicationInsights) | string | false | |
| defaultUserAccountLogin | The identifier of the user to create when starting the License Management cluster on an empty database. The user account should already exist in authentication provider. | string | false | |
| logLevel | Log level for License Management containers | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| clusterResiliencyPolicies | Cluster resiliency policies | Cluster resiliency policies | false | |
| strategy | Kubernetes deployment strategy fallback (spec.strategy) |
object | false | global.deployment.strategy |
Backend
The following properties can be set on the backend property of the License Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | licenseManagement.strategy |
TaskRunner
The following properties can be set on the taskRunner property of the License Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | licenseManagement.strategy |
Frontend
The following properties can be set on the frontend property of the License Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of frontend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 64Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | licenseManagement.strategy |
API Documentation (Swagger)
By default, the API documentation UI (Swagger) is not exposed.
You can configure it by setting the following properties on the apiDocumentation property of the License Management configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable API documentation interface | boolean | false | false |
| prefix | Prefix for API documentation access (eg: https://<host>/<prefix>/) |
string | false | api-documentation |
Task Scheduler
Task Scheduler cluster allows to schedule background server methods in Neos clusters.
Note
Task Scheduler configuration is only mandatory if you need to execute scheduled tasks.
Common
The following properties can be set on the taskScheduler property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| databaseType | Database persistence type (Oracle, PostgreSQL or SqlServer) | string | true | |
| host | Domain for Task Scheduler access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| envSecret | Secret name for backend taskScheduler container env variables (at least PersistenceSettings__ConnectionString) | string | false | |
| jsonConfigurationSecret | Secret name for taskScheduler frontend container additional configuration (like ApplicationInsights) | string | false | |
| defaultUserAccountLogin | The identifier of the user to create when starting the Task Scheduler cluster on an empty database. The user account should already exist in authentication provider. | string | false | |
| logLevel | Log level for Task Scheduler containers | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| clusterResiliencyPolicies | Cluster resiliency policies | Cluster resiliency policies | false | |
| strategy | Kubernetes deployment strategy fallback (spec.strategy) |
object | false | global.deployment.strategy |
Backend
The following properties can be set on the backend property of the Task Scheduler configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | taskScheduler.strategy |
TaskRunner
The following properties can be set on the taskRunner property of the Task Scheduler configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | taskScheduler.strategy |
Frontend
The following properties can be set on the frontend property of the Task Scheduler configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of frontend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 64Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | taskScheduler.strategy |
API Documentation (Swagger)
By default, the API documentation UI (Swagger) is not exposed.
You can configure it by setting the following properties on the apiDocumentation property of the Task Scheduler configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable API documentation interface | boolean | false | false |
| prefix | Prefix for API documentation access (eg: https://<host>/<prefix>/) |
string | false | api-documentation |
Neos AI
Neos AI cluster allows to monitor the AI usage.
Common
The following properties can be set on the neosAI property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| databaseType | Database persistence type (Oracle, PostgreSQL or SqlServer) | string | true | |
| host | Domain for Neos AI access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| envSecret | Secret name for backend neosAI container env variables (at least PersistenceSettings__ConnectionString) | string | false | |
| jsonConfigurationSecret | Secret name for Neos AI frontend container additional configuration (like ApplicationInsights) | string | false | |
| defaultUserAccountLogin | The identifier of the user to create when starting the Neos AI cluster on an empty database. The user account should already exist in authentication provider. | string | false | |
| logLevel | Log level for Neos AI containers | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| clusterResiliencyPolicies | Cluster resiliency policies | Cluster resiliency policies | false | |
| strategy | Kubernetes deployment strategy fallback (spec.strategy) |
object | false | global.deployment.strategy |
Backend
The following properties can be set on the backend property of the Neos AI configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | neosAI.strategy |
TaskRunner
The following properties can be set on the taskRunner property of the Neos AI configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | neosAI.strategy |
Frontend
The following properties can be set on the frontend property of the Neos AI configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of frontend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 64Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | neosAI.strategy |
API Documentation (Swagger)
By default, the API documentation UI (Swagger) is not exposed.
You can configure it by setting the following properties on the apiDocumentation property of the Neos AI configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable API documentation interface | boolean | false | false |
| prefix | Prefix for API documentation access (eg: https://<host>/<prefix>/) |
string | false | api-documentation |
Support Center
Support Center cluster allows to view errors reported by users.
Common
The following properties can be set on the supportCenter property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| databaseType | Database persistence type (Oracle, PostgreSQL or SqlServer) | string | true | |
| host | Domain for Support Center access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| envSecret | Secret name for backend supportCenter container env variables (at least PersistenceSettings__ConnectionString) | string | false | |
| jsonConfigurationSecret | Secret name for supportCenter frontend container additional configuration (like ApplicationInsights) | string | false | |
| defaultUserAccountLogin | The identifier of the user to create when starting the Support Center cluster on an empty database. The user account should already exist in authentication provider. | string | false | |
| logLevel | Log level for Support Center containers | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| clusterResiliencyPolicies | Cluster resiliency policies | Cluster resiliency policies | false | |
| strategy | Kubernetes deployment strategy fallback (spec.strategy) |
object | false | global.deployment.strategy |
Backend
The following properties can be set on the backend property of the Support Center configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | supportCenter.strategy |
TaskRunner
The following properties can be set on the taskRunner property of the Support Center configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | supportCenter.strategy |
Frontend
The following properties can be set on the frontend property of the Support Center configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| replicas | Desired number of frontend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 64Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | supportCenter.strategy |
API Documentation (Swagger)
By default, the API documentation UI (Swagger) is not exposed.
You can configure it by setting the following properties on the apiDocumentation property of the Support Center configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable API documentation interface | boolean | false | false |
| prefix | Prefix for API documentation access (eg: https://<host>/<prefix>/) |
string | false | api-documentation |
Redis
Redis is used for distributed cache (and possibly as message broker).
It is deployed as a dependency for the Neos Helm chart. It uses the Bitnami Redis chart associated to a Redis stack image.
By default, only one Redis server instance is deployed and shared between Neos components, separated by database.
Thus, the configuration can be set using the redis property of the main configuration.
Note
If you want to deploy specific instances for each Neos components, please see this section.
Protecting Redis with a password
By default Redis is deployed without authentication so any pod in the internal network can connect to it just by knowing its service address.
To protect the instance with a password, you can configure a password file in the Helm values file.
For example, you can create a secret using the following command :
kubectl create secret generic redis-password-secret --from-literal redis-password=<YOUR-PASSWORD>
Then, you can configure the Helm values file with your secret :
redis:
auth:
enabled: true
usePassword: true
usePasswordFile: true
existingSecret: redis-password-secret
Using Redis persistence
By default, Redis is deployed without persistence so all data is lost if any Redis pod is restarted.
To enable persistence, you need to create a PersistentVolumeClaim and configure the Helm values file with the claim name.
Note
To create a PVC, you can create a new yaml file (ex: my-redis-pvc.yaml) :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: 'my-redis-pvc' # The name that will be used to reference this PVC in the deployment
namespace: 'your-kubernetes-namespace' # The kubernetes namespace where your cluster is deployed
spec:
accessModes:
- ReadWriteMany # https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
resources:
requests:
storage: '1Gi' # The amount of storage that will be allocated to the PVC
storageClassName: 'your-storage-class-name' # The name of the storage class that will be used to provision the PVC
Then apply it on your kubernetes cluster using the kubectl apply command :
kubectl apply -n your-kubernetes-namespace -f my-redis-pvc.yaml
The PVC should be created in the same namespace as your Neos cluster, the master.persistence.enabled property should be set to true and the master.persistence.existingClaim property should be set with the PVC name.
redis:
master:
persistence:
enabled: true
existingClaim: my-redis-pvc
Note
For specific instances for Neos components, you can set the master.persistence.enabled and master.persistence.existingClaim properties for each instance (see this section).
Note that you'll need to create a PVC for each instance if you want to use persistence for multiple instances.
Troubleshooting
PVC and PV status
If you have issues with the Redis pods not starting when using persistence, make sure that the PVC is correctly bound to a PersistentVolume and that the PersistentVolume is correctly provisioned. You can check the status of the PVC and the PersistentVolume using the following commands:
kubectl get pvc -n your-kubernetes-namespace
kubectl get pv -n your-kubernetes-namespace
The PVC should be in Bound status and the PV should be in Available or Bound status. If the PV is in Available status, it means that it is not yet bound to the PVC and you may need to check your storage class configuration.
If the PV is in Bound status but the Redis pods are still not starting, you can check the events of the PVC and the PV for any error messages using the following commands:
kubectl describe pvc my-redis-pvc -n your-kubernetes-namespace
kubectl describe pv my-pv-name -n your-kubernetes-namespace
If there are any issues with the storage provisioning, you may see error messages in the events section of the PVC or PV description.
If the issue persists, you may need to contact your Kubernetes administrator or storage provider for further assistance (see Hexanet wiki for Hexanet support).
Backup and restore
To backup and restore Redis data, you can use the Redis RDB snapshots feature. You can create a backup of your Redis data by copying the RDB file from the Redis pod to your local machine.
Please see this Powershell script for backup and restore operations on a Kubernetes cluster.
High availability in production (with Sentinel)
Warning
Dapr currently doesn't support authentication in Sentinel/Cluster mode so you should only deploy Redis in standalone mode (which is default in the Neos chart).
By default, the Neos chart will deploy a Redis instance in standalone mode (only one pod).
This is sufficient in a development environment but since this is a single point of failure, you should activate multiple replication in production.
To do so, you can enable high availability using Redis Sentinel by configuration your helm values file as following :
redis:
architecture: replication # default standalone
sentinel:
enabled: true # enable Redis Sentinel
Using a remote Redis instance
If you don't want to use the Redis deployment from the Neos chart, you can disable it and specify your own instance.
This is done by creating the externalRedisInstance property in the main configuration with the following properties and setting redis.enabled property value to false.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| host | The redis host (ex: 12.34.56.78:1234, myredisinstance:6379, asentinelcluster:26379) |
string | true | |
| sentinelMasterName | The master name if Redis is in Sentinel mode | string | false | |
| existingSecret | Name of the Kubernetes Secret containing the Redis password (key: redis-password) |
string | false |
Example:
redis:
enabled: false # Prevent the Redis instance to be deployed by Neos
externalRedisInstance:
host: my-redis-instance:26379
sentinelMasterName: myMaster # Optional :
Deploying specific instances for Neos components
By default, Neos components use the same Redis instance but are separated by database.
Neos state store will always use the Redis instance configured under the redis property of the Helm values file.
However, it is possible to enable deployment of specific Redis instances for the following components by setting their enabled property to true:
| Neos component | Redis database number | Specific Redis instance in Helm values file |
|---|---|---|
| Neos state store | 0 | redis (default) |
| Notification hub (SignalR) | 1 | redisSignalR |
| Neos gateway (distributed cache) | 2 | redisGateway |
| Background tasks (Dapr workflow actor) | 3 | redisActor |
In the following example, one specific instance of Redis is deployed for the notification hub with some specific resource (extended memory request/limit) but with the same authentication config.
# Base Redis instance for Neos state store, background tasks and gateway.
redis:
auth:
enabled: true
usePassword: true
usePasswordFile: true
existingSecret: redis-password-secret
# Specific instance for notification hub.
redisSignalR:
enabled: true
master:
resources:
requests:
memory: '512Mi' # Default 256Mi
cpu: '300m' # Default 150m
limits:
memory: '512Mi' # Default 256Mi
auth: # Use the same authentication config as the base instance
enabled: true
usePassword: true
usePasswordFile: true
existingSecret: redis-password-secret
Warning
Authentication is not shared by all instances, it has to be configured for each deployed Redis instance even if it use the same secret.
Warning
Using a remote instance will only replace redis instance. If you configure specific instance for other components, the specific instance will be deployed and used.
Task runner actor state store (Dapr workflow)
Neos ecosystem relies on Dapr workflow components for its background server methods to run.
In the Kubernetes cluster, a specific actor state store component needs to be configured. See this article for supported state stores.
Neos Helm chart generates the component specs for Redis and PostgreSQL (v1).
The following configurations can be set on the actorStateStore property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| preset | Actor state store preset | redis/postgresql/custom |
false | postgresql |
| postgresqlConnectionStringSecret | PostgreSQL database connection string secret name (if preset is postgresql) |
string | true if preset is postgresql |
|
| customSpec | Custom Dapr actor state store spec definition | yaml | true if preset is custom |
Warning
Redis is not recommended by Dapr as actor state store in production due to its limitations regarding transactions.
Example (PostgreSQL) :
actorStateStore:
preset: postgresql
postgresqlConnectionStringSecret: neos-actor-state-store-postgresql-secret
Example (custom for SQL Server) :
actorStateStore:
preset: custom
customSpec:
type: state.sqlserver
version: v1
metadata:
# Authenticate using SQL Server credentials
- name: connectionString
secretKeyRef:
name: neos-actor-state-store-sqlserver-secret
key: connectionString
- name: actorStateStore
value: 'true'
Warning
Don't forget to set the actorStateStore metadata property to "true" to configure the state store as an actor state store.
Inter cluster communication (Dapr)
Inter cluster communication is handled by Dapr. The following configurations can be set on the interClusterCommunication property of the main configuration.
Publication / Subscription
Publication / subscription communication is handled by Dapr.
By default, the Helm chart will deploy a RabbitMQ instance as a message broker for publication / subscription communication.
It is also possible to use the deployed Redis instance instead of RabbitMQ by setting the pubSubMessageBroker value to Redis.
If you want to deploy another supported broker, you can set the pubSubMessageBroker value to custom.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| pubSubMessageBroker | Pub/Sub message broker preset | RabbitMQ/Redis/custom |
false | RabbitMQ |
| pubSubMessageBrokerCustomSpec | Custom Dapr supported broker spec definition | yaml | true if preset is custom |
RabbitMQ
If Publication / Subscription is handled by RabbitMQ. You can set the following properties on the rabbitmq property of the inter cluster communication configuration.
This will deploy a RabbitMQ instance (as a StatefulSet) in the Kubernetes cluster and configure Dapr to use it as a message broker.
Important
This configuration is not recommended for production.
For high availability, it is preferable to deploy a RabbitMQ cluster in custom broker spec section.
For a Hexanet deployment, see this article. For more info on the RabbitMQ operator, see this article.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 20m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 256Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| enabled | Automatic deployment of Rabbit MQ broker (reachable at neos-dapr-rabbitmq:5672) |
boolean | false | true |
| updateStrategy | Kubernetes stateful set update strategy (spec.updateStrategy) |
object | false | { "type": "RollingUpdate", "rollingUpdate": { "partition": 0 }} |
RabbitMQ persistence (volume)
If you don't configure any persistence for RabbitMQ instance, data will be lost each time the pod is restarted. To keep data between restart/failure, you can set the following properties on the volume property of RabbitMQ configuration.
Important
Do not use S3-backed or object storage for RabbitMQ persistence, as the lack of low-latency random I/O and POSIX locking can cause database corruption. Instead, always configure your PersistentVolumeClaim to use a high-performance StorageClass backed by Block Storage to ensure data integrity and broker stability.
The chart uses ReadWriteOnce as the default access mode, which is well-suited for block storage-backed StorageClasses.
Always ensure your StorageClass and PersistentVolume support the configured access mode.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| storageClassName | Name of the Kubernetes storage class to use | string | true | |
| pvcName | Name of the persistent volume claim resource to use. Will be created if it does not exist. | string | true | |
| size | Volume size | Memory resource units | false | 1Gi |
| accessMode | Persistent volume claim access mode | Volume access modes | false | ReadWriteOnce |
Configuration example
Here is an example of how to configure RabbitMQ persistence in your values file:
interClusterCommunication:
rabbitmq:
enabled: true
volume:
storageClassName: fast-ssd-block-storage
pvcName: rabbitmq-data
size: 10Gi
accessMode: ReadWriteOnce
Ensure that your storageClassName is backed by Block Storage and supports the ReadWriteOnce access mode for optimal performance and reliability.
Custom broker spec
If you set the pubSubMessageBroker value to custom, you'll be able to configure a specific configuration for the message broker.
Warning
If you want to deploy your own RabbitMQ instance, don't forget to set interClusterCommunication.rabbitmq.enabled value to false.
Note
Don't forget to restart all dotnet pods (backend, task-runners, report server) if you change your connection string so they can connect to the new instance.
Example : Using an existing RabbitMQ cluster deployed with Hexanet operator
Operator manifest :
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
name: RMQ-CLUSTER-NAME
namespace: NAMESPACE
annotations:
rabbitmq.com/operator-connection-uri: http://RMQ-CLUSTER-NAME.NAMESPACE.svc.cluster.local:5672
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- RMQ-CLUSTER-NAME
topologyKey: 'kubernetes.io/hostname'
replicas: 3
resources:
requests:
cpu: 1
memory: 2Gi
limits:
memory: 2Gi
persistence:
storageClassName: STORAGECLASS-NAME
storage: 2Gi
rabbitmq:
additionalConfig: |
cluster_partition_handling = pause_minority
disk_free_limit.relative = 1.0
collect_statistics_interval = 10000
log.console.level = info
default_user_tags.administrator = true
override:
statefulSet:
spec:
podManagementPolicy: 'OrderedReady'
service:
type: ClusterIP
Helm values file :
interClusterCommunication:
rabbitmq:
enabled: false # don't deploy RabbitMQ since we use an already existing RabbitMQ cluster
pubSubMessageBroker: custom
pubSubMessageBrokerCustomSpec:
type: pubsub.rabbitmq
version: v1
metadata:
- name: connectionString
secretKeyRef:
name: RMQ-CLUSTER-NAME-default-user
key: connection_string
Example : Using Azure Service Bus Queues instead of RabbitMQ (see this article on Dapr)
interClusterCommunication:
rabbitmq:
enabled: false # don't deploy RabbitMQ since we use Azure Service Bus Queues instead
pubSubMessageBroker: custom
pubSubMessageBrokerCustomSpec:
type: pubsub.azure.servicebus.queues
version: v1
metadata:
- name: connectionString
value: 'Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}'
Resiliency
Dapr can be configured with resiliency policies.
Global resiliency policy
By default, the global retry policy on a Neos environment is the following :
policies:
retries:
# Neos pubsub retry policy (5 retries with 10s delay between each retry)
neosPubsubRetries:
policy: constant
duration: 10s
maxRetries: 5
targets: # https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-deadletter/#retries-and-dead-letter-topics
components:
neos-pubsub:
inbound:
retry: neosPubsubRetries
outbound:
retry: neosPubsubRetries
If you want to override this policy, you can set the globalResiliencySpec property of the inter cluster communication configuration (see this article for details).
Example :
globalResiliencySpec:
policies:
retries:
DaprBuiltInServiceRetries: # Overrides default retry behavior for service-to-service calls
policy: exponential
maxInterval: 5s
maxRetries: -1 # Retries indefinitely
Cluster resiliency policies
If you want to apply cluster specific resiliency policies, you set the clusterResiliencyPolicies property of the inter cluster communication configuration (see this article for details).
Example :
clusterResiliencyPolicies:
circuitBreakers:
pubsubCB:
maxRequests: 1
interval: 8s
timeout: 45s
trip: consecutiveFailures > 8
retries:
retryForever:
policy: exponential
maxInterval: 15s
maxRetries: -1 # Retry indefinitely
timeouts:
general: 5s
Observability
Neos observability can be configured to collect and route traces, metrics, and logs to one or more backends. Depending on your setup, telemetry can be sent to Jaeger, Zipkin, Application Insights, or any OTLP-compatible external platform.
OpenTelemetry collector and OTLP settings
The chart exposes a dedicated observability section that centralizes collector deployment and the OTLP settings injected into .NET processes. For routing modes, signal flag rules, and Dapr tracing behavior, see OpenTelemetry collector configuration.
observability.collector.mode—auto(default),enabled, ordisabled.observability.otlp— OTLP endpoint, protocol, per-signal overrides, and pass-through SDK/Serilog arguments.observability.dapr.zipkinEndpoint— routes Dapr sidecar inter-cluster traces to an external Zipkin-compatible endpoint. Has no effect when the chart-generated collector is active (all legacy backends including Zipkin-only); in that case Dapr is automatically routed to the internal collector.
Note
During migration, legacy keys using enable are still supported (jaeger.enable, interClusterCommunication.zipkin.enable, interClusterCommunication.appInsights.enable).
New values should use enabled.
Important
The chart injects the endpoint, protocol, timeout, and per-signal overrides as both Kubernetes pod environment variables (read by AddOtlpExporter() via Environment.GetEnvironmentVariable()) and as entries in appsettings.json (read by the Serilog sink and other IConfiguration-based consumers). For additional OTLP exporter settings not modeled by the chart, use observability.otlp.additionalConfiguration (injected as pod environment variables) or observability.otlp.envFromSecretName (mounted as envFrom on backend pods) with keys supported by the OpenTelemetry OTLP exporter SDK documentation.
Warning
observability.collector.config.existingConfigMap and observability.collector.config.inline are mutually exclusive. Configure only one.
Warning
When config.inline or config.existingConfigMap is active, the chart injects OTLP env vars into all workloads pointing at the internal collector, but cannot verify that the custom configuration exposes OTLP receivers on those ports. For every auto-enabled signal, at least one OTLP endpoint must be declared — observability.otlp.global.endpoint or a per-signal endpoint (traces.endpoint, metrics.endpoint, logs.endpoint) — for each enabled signal. This requirement is enforced regardless of observability.otlp.enabled. Validation fails otherwise.
Collector properties
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| mode | Collector deployment mode: auto (default), enabled, or disabled |
string | false | auto |
| envFromSecretName | Optional Secret name mounted as envFrom.secretRef in the collector pod |
string | false | |
| resources.cpuRequest | CPU request for collector pods (see Resource Management for Pods and Containers) | CPU resource units | false | |
| resources.memory | Memory request and limit for collector pods (see Resource Management for Pods and Containers) | Memory resource units | false | |
| resources.memoryRequest | Memory request for collector pods, overrides resources.memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| resources.memoryLimit | Memory limit for collector pods, overrides resources.memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| config.existingConfigMap | Existing ConfigMap name used as collector configuration override (data.neos-otel-collector-config) |
string | false | |
| config.inline | Inline collector YAML override (replaces the generated neos-otel-collector-config.yaml) |
string | false | |
| config.debugExporterEnabled | Enable the internal collector debug exporter for troubleshooting |
boolean | false | false |
| strategy | Kubernetes deployment strategy for collector pods (spec.strategy) |
object | false | global.deployment.strategy |
Note
The default internal collector configuration exports traces to the enabled trace backends. It exports metrics and logs when interClusterCommunication.appInsights.enabled=true or observability.collector.config.debugExporterEnabled=true.
Important
observability.collector.mode=enabled alone is not a valid generated collector configuration.
When using the chart-generated collector config, also enable at least one exporter backend (interClusterCommunication.appInsights.enabled, interClusterCommunication.zipkin.enabled, jaeger.enabled, or observability.collector.config.debugExporterEnabled=true), or provide observability.collector.config.inline / observability.collector.config.existingConfigMap.
Note
With observability.collector.mode=auto (default), legacy backends (interClusterCommunication.appInsights.enabled, interClusterCommunication.zipkin.enabled, jaeger.enabled) implicitly activate collector routing. Set observability.collector.mode=disabled to force opt-out.
Note
Collector resources can be configured through observability.collector.resources.*.
For backward compatibility, if these keys are not set, the chart falls back to interClusterCommunication.appInsights.* resource settings.
OTLP properties
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Explicitly enable OTLP export for Neos processes in direct OTLP mode. Internal collector routing activates OTLP injection automatically. | boolean | false | false |
| tracesEnabled | Enable traces export. null means auto: enabled when OTLP routing is active, unless explicitly set to false. When disabled, the chart writes OTEL_TRACES_EXPORTER=none. |
boolean/null | false | null |
| metricsEnabled | Enable metrics export. null means auto: enabled for chart-generated collector pipelines that support metrics and in direct OTLP mode; disabled by default for custom collector configs. When disabled, the chart writes OTEL_METRICS_EXPORTER=none. |
boolean/null | false | null |
| logsEnabled | Enable logs export. null means auto: enabled for chart-generated collector pipelines that support logs and in direct OTLP mode; disabled by default for custom collector configs. When disabled, the chart writes OTEL_LOGS_EXPORTER=none and does not render Serilog.WriteTo[0]. |
boolean/null | false | null |
| global.endpoint | Default OTLP endpoint for all signals. Only effective in direct OTLP mode (no active internal collector). When the internal collector is active, workloads always target the internal collector URL regardless of this value. Use per-signal endpoint overrides (traces.endpoint, metrics.endpoint, logs.endpoint) to bypass the collector for individual signals. |
string | false | |
| global.protocol | Default OTLP protocol | grpc/http/protobuf |
false | grpc |
| global.timeoutMs | Default OTLP timeout (milliseconds) | integer | false | 10000 |
| traces.endpoint | Per-signal OTLP endpoint for traces. Injects OTEL_EXPORTER_OTLP_TRACES_ENDPOINT. Takes priority over global.endpoint for traces. |
string | false | |
| traces.protocol | Per-signal OTLP protocol for traces. Injects OTEL_EXPORTER_OTLP_TRACES_PROTOCOL. When set without traces.endpoint, the chart also injects OTEL_EXPORTER_OTLP_TRACES_ENDPOINT with the port derived from this protocol (4318 for http/protobuf). Takes priority over global.protocol for traces. |
grpc/http/protobuf |
false | |
| metrics.endpoint | Per-signal OTLP endpoint for metrics. Injects OTEL_EXPORTER_OTLP_METRICS_ENDPOINT. Takes priority over global.endpoint for metrics. |
string | false | |
| metrics.protocol | Per-signal OTLP protocol for metrics. Injects OTEL_EXPORTER_OTLP_METRICS_PROTOCOL. When set without metrics.endpoint, the chart also injects OTEL_EXPORTER_OTLP_METRICS_ENDPOINT with the port derived from this protocol (4318 for http/protobuf). Takes priority over global.protocol for metrics. |
grpc/http/protobuf |
false | |
| logs.endpoint | Per-signal OTLP endpoint for logs. Injects OTEL_EXPORTER_OTLP_LOGS_ENDPOINT and overrides the Serilog sink endpoint. Takes priority over global.endpoint for logs. |
string | false | |
| logs.protocol | Per-signal OTLP protocol for logs. Injects OTEL_EXPORTER_OTLP_LOGS_PROTOCOL and overrides the Serilog sink protocol. When set without logs.endpoint, the chart also injects OTEL_EXPORTER_OTLP_LOGS_ENDPOINT and the Serilog sink endpoint with the port derived from this protocol (4318 for http/protobuf). Takes priority over global.protocol for logs. |
grpc/http/protobuf |
false | |
| additionalConfiguration | Additional OTEL SDK environment variables injected into all .NET backend pods via env:. Applied to the native OTLP SDK only – not propagated to the Serilog sink. Chart-generated env: entries take precedence over same-name keys in this map. |
object | false | {} |
| additionalSerilogConfiguration | Additional arguments merged into Serilog.WriteTo[0].Args for all .NET workloads. Applied to the Serilog.Sinks.OpenTelemetry sink only – not propagated to the native OTLP SDK. Injected at WriteTo[0]; place custom sinks at index 1 or higher. |
object | false | {} |
| envFromSecretName | Optional name of a Kubernetes Secret mounted as envFrom on all .NET backend pods. Use for OTEL SDK keys read directly from environment variables (e.g. OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_COMPRESSION). Explicit env: entries generated by the chart take precedence. See Secret-backed OTEL env vars. |
string | false |
Signal truth table
See Effective rendering rules in the OpenTelemetry collector configuration article.
Auto mode truth table
See Auto mode behavior in the OpenTelemetry collector configuration article.
Dapr tracing properties
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| zipkinEndpoint | External Zipkin endpoint used by Dapr sidecars for inter-cluster traces (.../api/v2/spans). Ignored when the chart-generated collector configuration is active — in that case Dapr is automatically routed to the internal collector Zipkin receiver at neos-otel-collector:9411, regardless of which legacy backend (Application Insights, Jaeger, or Zipkin) activated it. When a custom collector configuration is in use (config.inline / existingConfigMap), this property must be set explicitly if Application Insights or Jaeger is also enabled; validation fails otherwise. Also effective when observability.collector.mode=disabled, or when Zipkin-only is active with a custom or disabled collector. |
string | false |
Additional OTEL configuration example
observability:
otlp:
enabled: true
global:
endpoint: https://otel-gateway.example.com:4317
protocol: grpc
timeoutMs: 15000
additionalConfiguration:
OTEL_EXPORTER_OTLP_COMPRESSION: gzip
OTEL_EXPORTER_OTLP_HEADERS: x-tenant-id=neos-devtest
Important
additionalConfiguration entries are injected as pod environment variables (env:) and are consumed by the native OpenTelemetry SDK only (traces, metrics). They are not forwarded to the Serilog sink. If the OTLP endpoint requires authentication, also configure the corresponding sink-level option through additionalSerilogConfiguration.
Do not put credentials or tokens directly in values files. Prefer secret-backed environment variables through envFromSecretName.
Additional Serilog sink configuration example
observability:
otlp:
enabled: true
global:
endpoint: https://otel-gateway.example.com:4317
protocol: grpc
additionalSerilogConfiguration:
headers: 'x-tenant-id=neos-devtest'
Warning
additionalSerilogConfiguration is injected at Serilog.WriteTo[0]. Place any custom sinks at index 1 or higher to avoid conflicts.
The keys endpoint and protocol are reserved and cannot be redefined through this map.
Note
The key resourceAttributes is merged with the chart-generated block rather than replaced. User-supplied sub-keys are added alongside the chart's service.name; when the same sub-key appears in both, the chart value wins. Use this to inject extra OpenTelemetry resource attributes, for example:
additionalSerilogConfiguration:
resourceAttributes:
deployment.environment: production
Per-signal endpoint routing
Use observability.otlp.traces.*, observability.otlp.metrics.*, and observability.otlp.logs.* to route individual signals to dedicated endpoints. Per-signal endpoints take priority over global.endpoint. When only a per-signal protocol is set and it differs from the global protocol, the chart rewrites the port in global.endpoint (4318 for http/protobuf, 4317 for grpc); when the protocols match, global.endpoint is used as-is. For full behavior details, see Per-signal endpoint routing.
Important
In direct OTLP mode (no active collector), every auto-enabled signal must have a resolvable endpoint. Setting observability.otlp.enabled: true with only a subset of per-signal endpoints (e.g., only metrics.endpoint) while leaving other signals on auto is not valid — those other signals are auto-enabled but have no endpoint to connect to. Either provide global.endpoint to cover all signals, explicitly disable unused signals with tracesEnabled: false / logsEnabled: false, or enable the internal collector.
Example — internal collector for traces (via Jaeger), dedicated external endpoints for metrics and logs:
jaeger:
enabled: true
observability:
otlp:
enabled: true
metricsEnabled: true # explicit: metrics bypass the generated collector
logsEnabled: true # explicit: logs bypass the generated collector
metrics:
endpoint: 'http://external-metrics.example.com:4317'
logs:
endpoint: 'http://external-logs.example.com:4318'
protocol: 'http/protobuf'
In this configuration the chart renders:
OTEL_EXPORTER_OTLP_ENDPOINTpointing to the internal collector (for traces).OTEL_EXPORTER_OTLP_METRICS_ENDPOINTpointing to the external metrics endpoint.OTEL_EXPORTER_OTLP_LOGS_ENDPOINTpointing to the external logs endpoint.Serilog.WriteTo[0].Args.endpointpointing to the external logs endpoint withHttpProtobufprotocol.
Important
When using a generated internal collector alongside per-signal endpoint overrides, set metricsEnabled: true and logsEnabled: true explicitly for the signals that bypass the collector. Without explicit flags, the generated Jaeger-backed collector has no metrics or logs pipeline, so auto mode would disable those signals.
Note
If only per-signal endpoints are configured (no global.endpoint, no active collector), OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_PROTOCOL are not injected. Only the per-signal environment variables and the Serilog endpoint are rendered. OTEL_EXPORTER_OTLP_TIMEOUT is still injected as a global timeout.
Examples
For common observability routing examples, see Basic Helm configuration.
Internal collector with ConfigMap override:
observability:
collector:
mode: enabled
config:
existingConfigMap: neos-custom-otel-collector-config
otlp:
global:
endpoint: 'http://neos-otel-collector:4317'
Internal collector with optional environment variables from Secret:
observability:
collector:
mode: enabled
envFromSecretName: neos-otel-collector-extra-env
Internal collector with dedicated resource tuning:
observability:
collector:
mode: enabled
resources:
cpuRequest: 100m
memoryRequest: 256Mi
memoryLimit: 512Mi
config:
debugExporterEnabled: true
Jaeger
You can optionally deploy Jaeger to monitor inter-cluster communication by setting the following properties on the top-level jaeger section.
The default configuration uses the All-in-one configuration with 10000 max stored traces (jaeger.storage.options.memory.max_traces) and nameOverride: neos-jaeger, but you can override it directly under the top-level jaeger section.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Deploy Jaeger using the Helm chart | boolean | false | false |
| host | Domain for Jaeger access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false |
Warning
The host property exposes the Jaeger UI outside the cluster through an Ingress rule. Traffic is routed through the Neos gateway, which enforces authentication. However, Jaeger provides no per-user authorization: any authenticated user can browse all traces. Do not configure host in production environments unless all authenticated users are allowed to access the full trace history.
Note
Enabling Jaeger deployment also activates an OpenTelemetry Collector instance so traces can be sent to Jaeger.
Note
When Jaeger is enabled, the Dapr sidecar tracing configuration is automatically set to forward inter-cluster traces to the internal OTel collector Zipkin receiver (neos-otel-collector:9411/api/v2/spans), which then exports them to Jaeger. No additional Dapr configuration is required.
Zipkin
Warning
Zipkin is deprecated. Prefer Jaeger.
You can optionally deploy Zipkin to monitor inter-cluster communication by setting the following properties on the zipkin section of the inter-cluster communication configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Create a Zipkin instance | boolean | false | false |
| host | Domain for Zipkin access (from outside the Kubernetes cluster) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 256Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | global.deployment.strategy |
Warning
The host property exposes the Zipkin UI outside the cluster through an Ingress rule. Traffic is routed through the Neos gateway, which enforces authentication. However, Zipkin provides no per-user authorization: any authenticated user can browse all traces. Do not configure host in production environments unless all authenticated users are allowed to access the full trace history.
Application Insights
You can send Dapr inter-cluster communication traces to Application Insights by setting the following properties on the appInsights section of the inter-cluster communication configuration.
Warning
This Application Insights section is a legacy SDK-era path and is deprecated for backend .NET observability. Prefer OpenTelemetry Collector routing and exporter configuration. See OpenTelemetry collector migration.
Important
When interClusterCommunication.appInsights.enabled=true, collector routing is activated automatically by the chart.
You can still set observability.collector.mode=enabled explicitly for clarity.
Note
To create the secret containing the Application Insights connection string, you can use the following command:
kubectl create secret generic <secret-name> --from-literal=APPINSIGHTS_CONNECTION_STRING="InstrumentationKey=1a11a111-1a1a-1111-a111-1aaa1a1a1a11;IngestionEndpoint=https://westeurope-5.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/;ApplicationId=2b22b222-2b2b-2222-b222-2bbb2b2b2b22"
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable sending Dapr traces to Application Insights | boolean | false | false |
| connectionStringSecret | Name of the secret containing the APPINSIGHTS_CONNECTION_STRING environment variable. Required when enabled=true and the chart-generated collector is active (no observability.collector.config.inline or existingConfigMap). When a custom collector config is in use, supply the connection string through a mechanism suited to your collector deployment. |
string | false | |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 400Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false |
Clusters
clusters is an array of business clusters and you can use the following configuration for each one of them :
Common
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| name | Cluster name | string | true | |
| version | Cluster version (mono-tenant) | string | true if multitenancy is false | |
| daprVersion | Dapr version to use for this cluster (mono-tenant) | string | false | |
| versions | Cluster versions (multi-tenants) | cluster version configuration | true if multitenancy is true | |
| databaseType | Database persistence type (Oracle, PostgreSQL or SqlServer) | string | false | |
| host | Domain for cluster access (from outside the Kubernetes cluster) | string | false | |
| prefix | URL path prefix for cluster access (for path-based routing) | string | false | |
| tlsSecret | Name of the secret containing the TLS certificate | string | false | |
| logLevel | Log level for business cluster | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| multitenancy | Cluster multitenancy mode | boolean | false | false |
| reportLegacyMode | Force legacy report persistence for this mono-tenant cluster when report.S3.configurationSecret is configured. Use it for cluster versions prior to 3.2. |
boolean | false | false |
| clusterResiliencyPolicies | Cluster resiliency policies | Cluster resiliency policies | false | |
| strategy | Kubernetes deployment strategy fallback for cluster deployments (spec.strategy) |
object | false | global.deployment.strategy |
| priorityClassName | Kubernetes PriorityClass for business-cluster pods. Only application-high is supported. |
string | false | Kubernetes default |
Pod priority class
Business-cluster pods can optionally use the application-high Kubernetes PriorityClass. Set priorityClassName: application-high on a cluster to apply it to its backend, frontend and task-runner pods. Omit the property to let Kubernetes use the default PriorityClass.
Note
PriorityClass is used to set a precedence in the kubernetes pod scheduling. I.e. if resources are scarce, the highest priority pod are more likely to be created than the default priority ones. One intended usage is to to discriminate production from non-production workload. If your workloads are deployed in a shared environment you should not use a high value class.
For multi-tenant clusters, it can also be set on a specific entry in clusters[].versions[]. A component-level value (backend, frontend or backend.taskRunner) overrides the version value, which overrides the cluster value.
clusters:
- name: Northwind
priorityClassName: application-high
# backend, frontend and task-runner pods use application-high
Multitenancy
If the cluster is configured in multitenancy mode it can have several versions running in the same namespace.
In this case, you need to configure the versions property of the cluster configuration as follows :
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| version | Cluster version | string | true | |
| daprVersion | Dapr version to use for this cluster version | string | false | |
| logLevel | Log level for business cluster | Log level | false | Information |
| logMetricsAndHealthChecks | Log requests for metrics and health check | boolean | false | false |
| reportLegacyMode | Force legacy report persistence for this cluster version when report.S3.configurationSecret is configured. Use it for versions prior to 3.2. |
boolean | false | false |
| strategy | Kubernetes deployment strategy fallback for this version (spec.strategy) |
object | false | clusters[].strategy |
| priorityClassName | Kubernetes PriorityClass for this version's pods. Only application-high is supported. |
string | false | clusters[].priorityClassName |
Backend
Note
Backend configuration is not mandatory.
The following properties can be set in two different places depending on the cluster's multitenant mode :
- in the
backendproperty of a mono-tenant cluster configuration (see this example) - in the
backendproperty of each version of theversionsarray property of a multi-tenant cluster configuration (see this example)
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| image | Name of the backend image to pull | string | true | |
| envSecret | Secret name for backend container env variables (at least PersistenceSettings__ConnectionString) | string | true | |
| reportingTempDirectoryAccessMode | Reporting temporary directory access mode (eg. for report interceptors). Accepted values : ReadOnly (default), ReadWrite. |
string | false | ReadOnly |
| useSecretAsEnv | Use secret as environnement variables instead of using Dapr secret store (see this article) | boolean | false | true |
| imagePullSecret | Secret name for docker registry authentication | string | false | |
| tag | Tag of the backend image to pull | string | false | latest |
| appDirectory | Cluster directory path in the backend container pull | string | false | /app |
| port | Backend exposed port | number | false | 7000 |
| replicas | Desired number of backend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | clusters[].versions[].strategy (multi-tenant) or clusters[].strategy (mono-tenant) |
| priorityClassName | Kubernetes PriorityClass for the backend pod. Only application-high is supported. |
string | false | Version or cluster value |
| annotations | Kubernetes pod annotations | Annotation array | false |
Warning
If you want to deploy a cluster backend image based on a Neos version prior to 1.20, you need to set useSecretAsEnv property to true.
For security reason, since version 1.20, cluster configuration is mounted using Dapr secret stores instead of environment variables.
This prevents an attacker who has compromised the backend container from retrieving confidential information simply by accessing the process's environment variables.
Indeed, the secret store allows the values to be retrieved from the store and stored in memory at the start of the application. Only the application knows how to retrieve them.
Persistent storage (Volumes)
This configuration enables Kubernetes storage classes to be used to mount volumes in the backend pod.
Note
Volume configuration is not mandatory.
The following properties can be set either on the following properties of the cluster backend configuration :
volume(object) if only one volume needs to be mountedvolumes(array) if one or more volumes need to be mounted
Volumes are linked to Kubernetes Persistent Volume Claims (PVC).
Note
To create a PVC, you can create a new yaml file (ex: my-cluster-backend-pvc.yaml) :
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: 'my-cluster-backend-pvc' # The name that will be used to reference this PVC in the deployment
namespace: 'your-kubernetes-namespace' # The kubernetes namespace where your cluster is deployed
spec:
accessModes:
- ReadWriteMany # https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
resources:
requests:
storage: '512Mi' # The amount of storage that will be allocated to the PVC
storageClassName: 'your-storage-class-name' # The name of the storage class that will be used to provision the PVC
Then apply it on your kubernetes cluster using the kubectl apply command :
kubectl apply -n your-kubernetes-namespace -f my-cluster-backend-pvc.yaml
Volume
If you just need one volume to be mounted on your cluster backend/taskrunner pods, you can set the following properties on the volume item.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| storageClassName | Name of the Kubernetes storage class to use | string | true | |
| mountPath | Volume mount path inside the backend pod | string | true | |
| pvcName | Name of the persistent volume claim resource to use. If not set, a PVC will be created for each new version. | string | false | |
| size | Volume size | Memory resource units | false | 512Mi |
| accessMode | Persistent volume claim access mode (if no PVC name is set) | Volume access modes | false | ReadWriteMany |
Warning
The volume can only be mounted on a single version of your cluster. To share data between clusters, please create a PVC and use the volumes property to reference it.
Warning
By default, if no pvcName is set within volume property, then a PVC will be created for each new cluster version. Meaning that if you update your cluster version, the previous PVC will not be used by the new version.
To preserve data from one version to another, you should set the pvcName property and use it in each deployment.
Volumes
If you need more than one volume to be mounted on your cluster backend/taskrunner pods or you want to share data between several clusters/versions, you can define the volumes array, each item properties defined as the following.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| mountPath | Volume mount path inside the backend pod | string | true | |
| pvcName | Name of the persistent volume claim resource to use. If not set, a PVC will be created for each new version. | string | true | |
| readOnly | Mount the volume as readonly on the pod filesystem | boolean | false | false |
Warning
Only existing PVC can be referenced in the array. To create a PVC, please see this article
Example
Following example is a deployment of two clusters, one has a single volume, the other has two volumes.
Both clusters will be able to share the same files under /mnt/shared-documents because they are linked by the same persistent volume claim shared-documents-pvc. However, only ClusterWithOneVolume will be able to write in the directory, because ClusterWithTwoVolume mounts the volume as read only.
clusters:
- name: ClusterWithOneVolume
# ... main cluster config ...
backend:
# ... cluster backend config ...
volumes:
- pvcName: shared-documents-pvc
mountPath: /mnt/shared-documents
- name: ClusterWithTwoVolume
# ... main cluster config ...
backend:
# ... cluster backend config ...
volumes:
- pvcName: shared-documents-pvc
mountPath: /mnt/shared-documents
readOnly: true
- pvcName: configuration-pvc
mountPath: /mnt/conf
Host aliases
Note
Host aliases configuration is not mandatory.
You can add additional host entries to your backend containers by configuring the hostAliases property of the cluster backend configuration.
Please see this article on Kubernetes documentation for more info.
Example : add a third party service IP to be resolved as a specific host
clusters:
- name: TechnicalDemos
# ... main cluster config ...
backend:
# ... cluster backend config ...
hostAliases:
- ip: '10.1.2.3'
hostnames:
- 'my-service.local'
In this example, if the backend create an http request on my-service.local, it will be send to the IP 10.1.2.3.
Task runner (TaskRunner)
Note
TaskRunner configuration is not mandatory.
You can configure it by setting the following properties on the taskRunner property of the cluster backend configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| image | Name of the task runner image to pull | string | true | |
| imagePullSecret | Secret name for docker registry authentication | string | false | |
| tag | Tag of the task runner image to pull | string | false | latest |
| port | Task runner exposed port | number | false | 7000 |
| replicas | Desired number of task runner instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 10m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 512Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | clusters[].versions[].backend.strategy (multi-tenant), then version/cluster/global fallback |
| priorityClassName | Kubernetes PriorityClass for the task-runner pod. Only application-high is supported. |
string | false | Backend, version or cluster value |
| annotations | Kubernetes pod annotations | Annotation array | false |
Dapr configuration
Note
Dapr configuration is not mandatory.
The following sections can be configured under the dapr property of each cluster backend property.
Workflow
The workflow property (object) can be specified to configure Dapr sidecar workflow (see the official documentation).
The following examples configures the Technical demos cluster sidecar (of its task-runner pod) so it can only create 2 concurrent workflow executions and 3 concurrent activity executions per task-runner replicas.
Example for a single deployed version :
clusters:
- name: TechnicalDemos
backend:
dapr:
workflow:
maxConcurrentWorkflowInvocations: 2
maxConcurrentActivityInvocations: 3
Example for several deployed versions of the same cluster :
clusters:
- name: TechnicalDemos
versions:
version: 1.0
backend:
dapr:
workflow:
maxConcurrentWorkflowInvocations: 2
maxConcurrentActivityInvocations: 3
version: 2.0
backend:
dapr:
workflow:
maxConcurrentWorkflowInvocations: 4
maxConcurrentActivityInvocations: 5
API Documentation (Swagger)
By default, the API documentation UI (Swagger) is not exposed.
You can configure it by setting the following properties on the apiDocumentation property of the cluster configuration.
Note
This configuration is only relevant if your cluster has a Neos cluster backend.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable API documentation interface | boolean | false | false |
| prefix | Prefix for API documentation access (eg: https://<host>/<prefix>/) |
string | false | api-documentation |
Frontend
Note
Frontend configuration is not mandatory.
The following properties can be set in two different places depending on the cluster's multitenant mode :
- in the
frontendproperty of a mono-tenant cluster configuration (see this example) - in the
frontendproperty of each version of theversionsarray property of a multi-tenant cluster configuration (see this example)
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| image | Name of the frontend image to pull | string | true | |
| imagePullSecret | Secret name for docker registry authentication | string | false | |
| tag | Tag of the frontend image to pull | string | false | latest |
| port | Frontend exposed port | number | false | 80 |
| replicas | Desired number of frontend instances | number | false | 1 |
| cpuRequest | CPU request (see Resource Management for Pods and Containers) | CPU resource units | false | 5m |
| memory | Memory request and limit (see Resource Management for Pods and Containers) | Memory resource units | false | 64Mi |
| memoryRequest | Memory request, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| memoryLimit | Memory limit, overrides memory if set (see Resource Management for Pods and Containers) |
Memory resource units | false | |
| strategy | Kubernetes deployment strategy (spec.strategy) |
object | false | clusters[].versions[].strategy (multi-tenant) or clusters[].strategy (mono-tenant) |
| priorityClassName | Kubernetes PriorityClass for the frontend pod. Only application-high is supported. |
string | false | Version or cluster value |
| env | List of environment variables injected into the frontend container (spec.containers[].env) |
array | false | |
| envFrom | List of environment variable sources injected into the frontend container (spec.containers[].envFrom). Supports secretRef and configMapRef |
array | false | |
| jsonConfigurationSecret | Secret name for cluster frontend container additional configuration (like ApplicationInsights) | string | false | |
| annotations | Kubernetes pod annotations | Annotation array | false |
Note
Kubernetes applies env entries directly on the container and envFrom as bulk imports from external sources.
If the same key exists in both, explicit values in env should be preferred to avoid ambiguity and keep configuration deterministic.
Example for a business cluster frontend serving a non-Neos service with environment-dependent configuration:
clusters:
- name: DocumentationPortal
version: nightly
databaseType: PostgreSQL
frontend:
image: harbor.hexanet.fr:8443/custom/documentation-frontend
env:
- name: BASE_URL
value: "https://docs.example.com"
envFrom:
- secretRef:
name: documentation-frontend-secrets
- configMapRef:
name: documentation-frontend-config
In this example, BASE_URL is defined explicitly in env, while API_KEY can be provided by the documentation-frontend-secrets Secret and non-sensitive defaults can come from the documentation-frontend-config ConfigMap.
Nested clusters
If you want to access a cluster using another cluster url with a prefix, you can configure this "nested" cluster using the nestedClusters array property.
Note
An alternative to nested cluster configuration is to configure a path prefix for the cluster using the prefix property. This will allow you to access the cluster with a path prefix without nesting it in another cluster.
Please see this article for configuring path prefix for cluster access without nesting.
For example, you have a cluster TechnicalDemos and a cluster TrackingDemo.
You want to display a TrackingDemo page directly in a UI of TechnicalDemos.
To do so in production, you can set the following configuration to the helm chart configuration file :
clusters:
- name: TechnicalDemos
host: technical-demos.example.com
nestedClusters:
- name: TrackingDemo
pathPrefix: tracking
forwardUserNotificationsToMainCluster: true
- name: TrackingDemo
host: tracking-demo.example.com
In this example, you should be able to access TrackingDemo cluster with the url https://technical-demos.example.com/tracking/.
By default, user notifications emitted by the nested cluster are not forwarded to the main cluster notification center. Setting forwardUserNotificationsToMainCluster to true enables this forwarding.
For more information, see this article.
Nesting Neos internal clusters (Tenant Management, License Management, ...)
Neos internal clusters can also be nested to avoid creating a specific DNS entry for each.
Available cluster names are :
TenantManagement(Tenant Management cluster)LicenseManagement(License Management cluster)TaskScheduler(Task Scheduler cluster)NeosAI(Neos AI cluster)
The following example configure Neos internal clusters as nested cluster of technical demos cluster so they can be accessed using :
https://technical-demos.example.com/tenantsfor Tenant Management clusterhttps://technical-demos.example.com/licensesfor License Management clusterhttps://technical-demos.example.com/schedulerfor Task Scheduler clusterhttps://technical-demos.example.com/aifor Neos AI cluster
clusters:
- name: TechnicalDemos
host: technical-demos.example.com
nestedClusters:
- name: TenantManagement
pathPrefix: tenants
- name: LicenseManagement
pathPrefix: licenses
- name: TaskScheduler
pathPrefix: scheduler
- name: NeosAI
pathPrefix: ai
Preset
Resources (cpu / memory) and replicas can be initialized with the preset value.
Valid values : Development or Production
Note
Preset configuration is not mandatory, by default it is set to Development.
Note
Preset configuration can be overridden by setting specific replicas, cpuRequests and memory.
(replicas / cpu / memory) Development |
(replicas / cpu / memory) Production |
|
|---|---|---|
| Gateway | 1 / 10m / 512Mi | 3 / 25m / 512Mi |
| Report | 1 / 10m / 1024Mi | 3 / 25m / 2048Mi |
| Tenant Management backend | 1 / 10m / 1024Mi | 3 / 20m / 1024Mi |
| Tenant Management task-runner | 1 / 10m / 1024Mi | 3 / 20m / 1024Mi |
| Tenant Management frontend | 1 / 5m / 64Mi | 3 / 5m / 64Mi |
| License Management backend | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| License Management task-runner | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| License Management frontend | 1 / 5m / 64Mi | 3 / 5m / 64Mi |
| Task Scheduler backend | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Task Scheduler task-runner | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Task Scheduler frontend | 1 / 5m / 64Mi | 3 / 5m / 64Mi |
| Neos AI backend | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Neos AI task-runner | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Neos AI frontend | 1 / 5m / 64Mi | 3 / 5m / 64Mi |
| Support Center backend | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Support Center task-runner | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Support Center frontend | 1 / 5m / 64Mi | 3 / 5m / 64Mi |
| RabbitMQ | 1 / 20m / 256Mi | 1 / 40m / 512Mi |
| Zipkin | 1 / 5m / 256Mi | 1 / 5m / 256Mi |
| Open telemetry collector (AppInsights) | 1 / 10m / 400Mi | 3 / 10m / 400Mi |
| Cluster backend / task-runner | 1 / 10m / 512Mi | 3 / 20m / 512Mi |
| Cluster frontend | 1 / 5m / 64Mi | 3 / 5m / 64Mi |
Note
Redis deployment should be handled separately according to the Bitnami chart. See this link for activating high availability in production.
Misc
Prometheus
The following properties can be set on the prometheus property of the main configuration.
| Property | Description | Type | mandatory | default |
|---|---|---|---|---|
| enabled | Enable Prometheus monitoring for Neos components. Set to false if no Prometheus operator is installed to prevent the chart from creating PodMonitor custom resources. |
boolean | false | true |
| promStackReleaseName | Helm release name for the Prometheus stack used for monitoring Neos components (sets the release label on generated PodMonitor resources, used by the Prometheus operator selector). |
string | false | prom-stack |
Exposing Dapr sidecar metrics to a specific Prometheus stack
By default, Dapr sidecar metrics are configured to be scraped by the Hexanet default Prometheus stack (deployed via Helm as prom-stack release).
It can be changed to your own release name by setting the prometheus.promStackReleaseName string property at the root of your helm chart configuration file.
Disabling prometheus
If Prometheus stack is not installed in your kubernetes cluster, you may need to set prometheus.enabled boolean property to false (default is true) so the chart will not try to create any specific custom resource definition (eg. PodMonitor for Prometheus operator).
Examples
Without Tenant Management
In this example, we expose one cluster (Northwind) without multitenancy :
gateway:
envSecret: neos-gateway-auth
report:
envSecret: neos-report-licence
clusters:
- name: Northwind
version: '1.2.3'
databaseType: 'PostgreSQL'
logLevel: 'Debug' # (default "Information")
tlsSecret: 'northwind-secret-name'
backend:
image: 'harbor.hexanet.fr:8443/neos/northwind-backend'
envSecret: northwind-env-secret
imagePullSecret: northwind-pull-secret # (optional)
tag: nightly # (default "latest")
replicas: 3 # (default 1)
appDirectory: /app # (default)
port: 7000 # (default)
volume:
storageClassName: example-nfs-server-storage-class
mountPath: /mnt/documents
size: 512Mi # (default)
accessMode: ReadWriteMany # (default)
frontend:
image: 'harbor.hexanet.fr:8443/neos/northwind-frontend'
jsonConfigurationSecret: northwind-frontend-conf
imagePullSecret: northwind-pull-secret # (optional)
port: 80 # (default)
replicas: 2 # (default 1)
tag: nightly # (default "latest")
host: 'northwind.example.local'
interClusterCommunication:
pubSubMessageBroker: Redis # (default RabbitMQ)
With multitenancy
In this example, we expose one multi tenant cluster (Northwind) with two different versions and the Tenant Management :
tenantManagement:
databaseType: 'PostgreSQL'
host: tenants.example.local
tlsSecret: tenants-tls-secret
envSecret: neos-tenants-env
jsonConfigurationSecret: neos-tenants-frontend-conf
defaultUserAccountLogin: '[email protected]' # (optional)
gateway:
envSecret: neos-gateway-auth
report:
envSecret: neos-report-licence
clusters:
- name: Northwind
databaseType: 'PostgreSQL'
tlsSecret: 'northwind-secret-name'
multitenancy: true # enable multi-tenant mode (default "false")
host: 'northwind.example.local'
versions:
- version: '1.2.3'
backend:
image: 'harbor.hexanet.fr:8443/neos/northwind-backend'
envSecret: northwind-env-secret
tag: '1.2.3'
frontend:
image: 'harbor.hexanet.fr:8443/neos/northwind-frontend'
jsonConfigurationSecret: northwind-frontend-conf
tag: '1.2.3'
- version: '1.2.4'
backend:
image: 'harbor.hexanet.fr:8443/neos/northwind-backend'
envSecret: northwind-env-secret
tag: '1.2.4'
frontend:
image: 'harbor.hexanet.fr:8443/neos/northwind-frontend'
jsonConfigurationSecret: northwind-frontend-conf
tag: '1.2.4'