Table of Contents

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 request
  • memoryLimit: 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: 1 allows 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 StatefulSet spec.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.updateStrategy for the RabbitMQ StatefulSet (spec.updateStrategy)
  • redis.master.updateStrategy for the main Redis statefulset
  • redisGateway.master.updateStrategy for the Redis statefulset used by the gateway
  • redisActor.master.updateStrategy for the Redis statefulset used for background tasks
  • redisSignalR.master.updateStrategy for the Redis statefulset used by SignalR (notifications)

Authentication

To provide authentication configuration to both gateway and notifications hub, 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
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/ and https://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 TechnicalDemos with no prefix (uses host)
  • Nested cluster Northwind with prefix northwind
  • 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.

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__ServiceURL for 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.modeauto (default), enabled, or disabled.
  • 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_ENDPOINT pointing to the internal collector (for traces).
  • OTEL_EXPORTER_OTLP_METRICS_ENDPOINT pointing to the external metrics endpoint.
  • OTEL_EXPORTER_OTLP_LOGS_ENDPOINT pointing to the external logs endpoint.
  • Serilog.WriteTo[0].Args.endpoint pointing to the external logs endpoint with HttpProtobuf protocol.
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

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

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

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 backend property of a mono-tenant cluster configuration (see this example)
  • in the backend property of each version of the versions array 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)
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 mounted
  • volumes (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
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 frontend property of a mono-tenant cluster configuration (see this example)
  • in the frontend property of each version of the versions array 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)
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/tenants for Tenant Management cluster
  • https://technical-demos.example.com/licenses for License Management cluster
  • https://technical-demos.example.com/scheduler for Task Scheduler cluster
  • https://technical-demos.example.com/ai for 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'