Configuration Guide
Overview
The CDN Manager is deployed via Helm chart with configuration supplied through values.yaml files. This guide explains the configuration structure, how to apply changes, and provides a reference for all configurable options.
Configuration Files
The installation ISO provides three configuration files at /mnt/esb3027/:
| File | Purpose |
|---|---|
values-lab.yaml | Recommended starting point for single-node lab deployments |
values-production.yaml | Recommended starting point for multi-node production deployments |
values.yaml | Complete reference of all configurable options with their defaults |
You only need to specify fields that differ from the defaults. Helm applies configuration hierarchically — values from your file override the chart’s built-in defaults, and any key you omit retains its default value.
Lab Configuration (values-lab.yaml)
values-lab.yaml is the recommended starting point for single-node lab, acceptance testing, and demonstration deployments. It pre-configures settings appropriate for a constrained single-node environment:
- Single Kafka controller replica (the default 3 replicas require 3 separate nodes to satisfy pod anti-affinity rules)
- Single Zitadel replica
- Self-signed TLS by default, with real certificate configuration commented out for reference
- Minimal resource requests suited to a single node
Copy the file to a writable location and edit it before deploying:
cp /mnt/esb3027/values-lab.yaml ~/values.yaml
The minimum required changes are:
- Set
global.hosts.manager[0].hostto your node’s hostname or IP address - Set
zitadel.zitadel.configmapConfig.ExternalDomainto the same value
These two values must match exactly or authentication will fail due to CORS policy violations. See Global Settings for details.
Production Configuration (values-production.yaml)
values-production.yaml is the recommended starting point for multi-node production deployments across a minimum three-node cluster. It pre-configures settings appropriate for a high-availability environment:
- Three Zitadel replicas spread across nodes for HA
- Production-grade resource requests and limits for all major components
- Kafka with a dedicated single-replica StorageClass (avoiding unnecessary triple-redundancy on top of Kafka’s own quorum)
- Manager HPA configured to scale between 3 and 8 replicas
- TLS certificate configuration with clearly marked placeholders
Copy the file to a writable location and edit it before deploying:
cp /mnt/esb3027/values-production.yaml ~/values.yaml
The minimum required changes before deploying are:
- Set
global.hosts.manager[0].hostto your primary manager hostname - Set
zitadel.zitadel.configmapConfig.ExternalDomainto the same hostname - Replace the placeholder TLS certificate and key in the
ingress.secretssection, and update thesecretNamevalues inmibFrontend.ingress.extraTlsandzitadel.ingress.tlsto match - Update
global.hosts.routerswith your CDN Director instances
See TLS Configuration and Global Settings for full details.
Hardware requirements: For per-node hardware specifications, refer to the System Requirements Guide. The System Requirements Guide is the authoritative source — the hardware comments in the header of
values-production.yamlmay not reflect the current requirements.
Complete Reference (values.yaml)
The full default values file at /mnt/esb3027/values.yaml documents every configurable option with its default value and inline comments. Use this as a reference when looking up available settings or understanding what the environment-specific files override.
Note:
values.yamlis not intended to be used directly as your deployment configuration. Usevalues-lab.yamlorvalues-production.yamlas your starting point instead.
Configuration Merging
Helm merges configuration files from left to right, with later files overriding earlier values. This allows you to split your configuration into multiple files — for example, keeping TLS certificates separate from the main configuration:
# Multiple files merged left-to-right
helm install acd-manager /mnt/esb3027/charts/acd-manager \
--values ~/values.yaml \
--values ~/values-tls.yaml
Individual Value Overrides
For temporary changes, you can override individual values with --set:
helm upgrade acd-manager /mnt/esb3027/helm/charts/acd-manager \
--values ~/values.yaml \
--set manager.logLevel=debug
Note: Using --set is discouraged for permanent changes, as the same arguments must be specified for every Helm operation.
Applying Configuration
Initial Installation
helm install acd-manager /mnt/esb3027/charts/acd-manager \
--values ~/values.yaml
Updating Configuration
helm upgrade acd-manager /mnt/esb3027/helm/charts/acd-manager \
--values ~/values.yaml
Dry Run
Before applying changes, validate the configuration with a dry run:
helm upgrade acd-manager /mnt/esb3027/helm/charts/acd-manager \
--values ~/values.yaml \
--dry-run
Rollback
If an upgrade fails, rollback to the previous revision:
# View revision history
helm history acd-manager
# Rollback to previous revision
helm rollback acd-manager
# Rollback to specific revision
helm rollback acd-manager <revision_number>
Note: Rollback reverts the Helm release but does not modify your values.yaml file. You must manually revert configuration file changes.
Force Reinstall
If an upgrade fails and rollback is not sufficient, you can perform a clean reinstall:
helm uninstall acd-manager
helm install acd-manager /mnt/esb3027/charts/acd-manager \
--values ~/values.yaml
Warning: This is service-affecting as all pods will be destroyed and recreated.
Configuration Reference
Global Settings
The global section contains cluster-wide settings. The most critical configuration is global.hosts.
global:
hosts:
manager:
- host: manager.local
routers:
- name: default
address: 127.0.0.1
edns_proxy: []
geoip: []
| Key | Type | Description |
|---|---|---|
global.hosts.manager | Array | External IP addresses or DNS hostnames for all Manager cluster nodes |
global.hosts.routers | Array | CDN Director (ESB3024) instances |
global.hosts.edns_proxy | Array | EDNS Proxy addresses (currently unused) |
global.hosts.geoip | Array | GeoIP Proxy addresses for Frontend GUI |
Important: The first entry in global.hosts.manager must match zitadel.zitadel.ExternalDomain exactly. Zitadel enforces CORS protection, and authentication will fail if these do not match.
Manager Configuration
Core Manager API server settings:
| Key | Type | Default | Description |
|---|---|---|---|
manager.image.registry | String | ghcr.io | Container image registry |
manager.image.repository | String | edgeware/acd-manager | Container image repository |
manager.image.tag | String | Image tag override (uses latest if empty) | |
manager.logLevel | String | info | Log level (trace, debug, info, warn, error) |
manager.replicaCount | Number | 1 | Number of replicas (HPA manages this when enabled) |
manager.containerPorts.http | Number | 80 | HTTP container port |
manager.maxmindDbVolume | String | Name of PVC containing MaxMind GeoIP databases |
Manager Resources
The chart supports both resource presets and explicit resource specifications:
| Key | Type | Default | Description |
|---|---|---|---|
manager.resourcesPreset | String | `` (empty) | Resource preset (see Resource Presets table). Ignored if manager.resources is set. |
manager.resources.requests.cpu | String | 300m | CPU request |
manager.resources.requests.memory | String | 512Mi | Memory request |
manager.resources.limits.cpu | String | 1 | CPU limit |
manager.resources.limits.memory | String | 4Gi | Memory limit |
Note: For production workloads, explicitly set manager.resources rather than using presets.
Manager Datastore
manager:
datastore:
type: redis
namespace: "cdn_manager_ds"
default_ttl: ""
compression: zstd
| Key | Type | Default | Description |
|---|---|---|---|
manager.datastore.type | String | redis | Datastore backend type |
manager.datastore.namespace | String | cdn_manager_ds | Redis namespace for manager data |
manager.datastore.default_ttl | String | `` (empty) | Default TTL for entries |
manager.datastore.compression | String | zstd | Compression algorithm (none, zstd, etc.) |
Manager Discovery
manager:
discovery: []
# Example:
# - namespace: "other"
# hosts:
# - other-host1
# - other-host2
# pattern: "other-.*"
| Key | Type | Description |
|---|---|---|
manager.discovery | Array | Array of discovery host configurations. Each entry can specify hosts (list of hostnames), pattern (regex pattern), or both |
Manager Tuning
manager:
tuning:
enable_cache_control: true
cache_control_max_age: "5m"
cache_control_miss_max_age: ""
| Key | Type | Default | Description |
|---|---|---|---|
manager.tuning.enable_cache_control | Boolean | true | Enable cache control headers in responses |
manager.tuning.cache_control_max_age | String | 5m | Maximum age for cache control headers |
manager.tuning.cache_control_miss_max_age | String | `` (empty) | Maximum age for cache control headers on cache misses |
Manager Container Arguments
manager:
args:
- --config-file=/etc/manager/config.toml
- http-server
Gateway Configuration
NGinx Gateway settings for external Director communication:
| Key | Type | Default | Description |
|---|---|---|---|
gateway.replicaCount | Number | 1 | Number of gateway replicas |
gateway.resources.requests.cpu | String | 100m | CPU request |
gateway.resources.requests.memory | String | 128Mi | Memory request |
gateway.resources.limits.cpu | String | 150m | CPU limit |
gateway.resources.limits.memory | String | 192Mi | Memory limit |
gateway.service.type | String | ClusterIP | Service type |
MIB Frontend Configuration
Web-based configuration GUI settings:
| Key | Type | Default | Description |
|---|---|---|---|
mib-frontend.enabled | Boolean | true | Enable the frontend GUI |
mib-frontend.frontend.resourcePreset | String | nano | Resource preset |
mib-frontend.frontend.autoscaling.hpa.enabled | Boolean | true | Enable HPA |
mib-frontend.frontend.autoscaling.hpa.minReplicas | Number | 2 | Minimum replicas |
mib-frontend.frontend.autoscaling.hpa.maxReplicas | Number | 4 | Maximum replicas |
Confd Configuration
Confd settings for configuration management:
| Key | Type | Default | Description |
|---|---|---|---|
confd.enabled | Boolean | true | Enable Confd |
confd.service.ports.internal | Number | 15000 | Internal service port |
VictoriaMetrics Configuration
Time-series database for metrics:
| Key | Type | Default | Description |
|---|---|---|---|
acd-metrics.enabled | Boolean | true | Enable metrics components |
acd-metrics.victoria-metrics-single.enabled | Boolean | true | Enable VictoriaMetrics |
acd-metrics.grafana.enabled | Boolean | true | Enable Grafana |
acd-metrics.telegraf.enabled | Boolean | true | Enable Telegraf |
acd-metrics.prometheus.enabled | Boolean | true | Enable Prometheus metrics |
Ingress Configuration
Traffic exposure settings:
| Key | Type | Default | Description |
|---|---|---|---|
ingress.enabled | Boolean | true | Enable ingress record generation |
ingress.pathType | String | Prefix | Ingress path type |
ingress.hostname | String | `` (empty) | Primary hostname (defaults to manager.local via global.hosts) |
ingress.path | String | /api | Default path for ingress |
ingress.tls | Boolean | false | Enable TLS configuration |
ingress.selfSigned | Boolean | false | Generate self-signed certificate via Helm |
ingress.secrets | Array | Custom TLS certificate secrets |
Ingress Extra Paths
The chart includes default extra paths for Confd and GeoIP:
ingress:
extraPaths:
- path: /confd
pathType: Prefix
backend:
service:
name: acd-manager-gateway
port:
name: http
- path: /geoip
pathType: Prefix
backend:
service:
name: acd-manager-gateway
port:
name: http
TLS Certificate Secrets
For production TLS certificates:
ingress:
secrets:
- name: manager.local-tls
key: |-
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
certificate: |-
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
tls: true
Resource Configuration
Resource Presets
Predefined resource configurations for common deployment sizes:
| Preset | Request CPU | Request Memory | Limit CPU | Limit Memory | Ephemeral Storage Limit |
|---|---|---|---|---|---|
nano | 100m | 128Mi | 150m | 192Mi | 2Gi |
micro | 250m | 256Mi | 375m | 384Mi | 2Gi |
small | 500m | 512Mi | 750m | 768Mi | 2Gi |
medium | 500m | 1024Mi | 750m | 1536Mi | 2Gi |
large | 1000m | 2048Mi | 1500m | 3072Mi | 2Gi |
xlarge | 1000m | 3072Mi | 3000m | 6144Mi | 2Gi |
2xlarge | 1000m | 3072Mi | 6000m | 12288Mi | 2Gi |
Note: Limits are calculated as requests plus 50% (except for xlarge/2xlarge and ephemeral-storage).
Custom Resources
Override preset with custom values:
manager:
resources:
requests:
cpu: "300m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
Note:
- CPU values use millicores (1000m = 1 core)
- Memory values use binary SI units (1024Mi = 1GiB)
- Requests represent minimum guaranteed resources
- Limits represent maximum consumable resources
Capacity Planning
When sizing resources:
- Requests determine scheduling (node must have available capacity)
- Limits prevent resource starvation
- Maintain 20-30% cluster headroom for scaling
- Total capacity = sum of all requests × replica count + headroom
Security Contexts
Pod Security Context
manager:
podSecurityContext:
enabled: true
fsGroup: 1001
fsGroupChangePolicy: Always
sysctls: []
supplementalGroups: []
Container Security Context
manager:
containerSecurityContext:
enabled: true
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
readOnlyRootFilesystem: true
privileged: false
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: "RuntimeDefault"
Health Probes
Probe Types
| Probe | Purpose | Failure Action |
|---|---|---|
startupProbe | Initial startup verification | Container restart |
readinessProbe | Traffic readiness check | Remove from load balancer |
livenessProbe | Health monitoring | Container restart |
Default Probe Configuration
Liveness Probe
manager:
livenessProbe:
enabled: true
initialDelaySeconds: 5
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
successThreshold: 1
httpGet:
path: /api/v1/health/alive
port: http
Readiness Probe
manager:
readinessProbe:
enabled: true
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 7
failureThreshold: 3
successThreshold: 1
httpGet:
path: /api/v1/health/ready
port: http
Startup Probe
manager:
startupProbe:
enabled: true
initialDelaySeconds: 0
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 10
successThreshold: 1
httpGet:
path: /api/v1/health/alive
port: http
Autoscaling Configuration
Horizontal Pod Autoscaler (HPA)
manager:
autoscaling:
hpa:
enabled: true
minReplicas: 3
maxReplicas: 8
targetCPU: 50
targetMemory: 80
| Key | Type | Default | Description |
|---|---|---|---|
manager.autoscaling.hpa.enabled | Boolean | true | Enable HPA |
manager.autoscaling.hpa.minReplicas | Number | 3 | Minimum number of replicas |
manager.autoscaling.hpa.maxReplicas | Number | 8 | Maximum number of replicas |
manager.autoscaling.hpa.targetCPU | Number | 50 | Target CPU utilization percentage |
manager.autoscaling.hpa.targetMemory | Number | 80 | Target Memory utilization percentage |
Network Policy
networkPolicy:
enabled: true
allowExternal: true
allowExternalEgress: true
addExternalClientAccess: true
| Key | Type | Default | Description |
|---|---|---|---|
networkPolicy.enabled | Boolean | true | Enable NetworkPolicy |
networkPolicy.allowExternal | Boolean | true | Allow connections from any source (don’t require pod label) |
networkPolicy.allowExternalEgress | Boolean | true | Allow pod to access any range of port and destinations |
networkPolicy.addExternalClientAccess | Boolean | true | Allow access from pods with client label set to “true” |
Pod Affinity and Anti-Affinity
manager:
podAffinityPreset: ""
podAntiAffinityPreset: soft
nodeAffinityPreset:
type: ""
key: ""
values: []
affinity: {}
| Key | Type | Default | Description |
|---|---|---|---|
manager.podAffinityPreset | String | `` (empty) | Pod affinity preset (soft or hard). Ignored if affinity is set |
manager.podAntiAffinityPreset | String | soft | Pod anti-affinity preset (soft or hard). Ignored if affinity is set |
manager.nodeAffinityPreset.type | String | `` (empty) | Node affinity preset type (soft or hard) |
manager.affinity | Object | {} | Custom affinity rules (overrides presets) |
Service Configuration
service:
type: ClusterIP
ports:
http: 80
annotations:
service.kubernetes.io/topology-mode: Auto
externalTrafficPolicy: Cluster
sessionAffinity: None
| Key | Type | Default | Description |
|---|---|---|---|
service.type | String | ClusterIP | Service type |
service.ports.http | Number | 80 | HTTP service port |
service.annotations | Object | service.kubernetes.io/topology-mode: Auto | Service annotations |
service.externalTrafficPolicy | String | Cluster | External traffic policy |
Persistence Configuration
persistence:
enabled: false
mountPath: /agiletv/manager/data
storageClass: ""
accessModes:
- ReadWriteOnce
size: 8Gi
| Key | Type | Default | Description |
|---|---|---|---|
persistence.enabled | Boolean | false | Enable persistence using PVC |
persistence.mountPath | String | /agiletv/manager/data | Mount path |
persistence.storageClass | String | `` (empty) | Storage class (uses cluster default if empty) |
persistence.size | String | 8Gi | Size of data volume |
RBAC and Service Account
rbac:
create: false
rules: []
serviceAccount:
create: true
name: ""
automountServiceAccountToken: true
annotations: {}
Metrics
metrics:
enabled: false
serviceMonitor:
enabled: false
namespace: ""
annotations: {}
labels: {}
interval: ""
scrapeTimeout: ""
| Key | Type | Default | Description |
|---|---|---|---|
metrics.enabled | Boolean | false | Enable Prometheus metrics export |
metrics.serviceMonitor.enabled | Boolean | false | Create Prometheus Operator ServiceMonitor |
Next Steps
After configuration:
- Installation Guide - Deploy with your configuration
- Operations Guide - Day-to-day management
- Performance Tuning Guide - Optimize system performance
- Architecture Guide - Understand component relationships