Standalone Nginx Ingress
In a multi-AZ deployment, each Kloudfuse cluster requires its own ingress-nginx controller pinned to its availability zone. Because the controller must be independently manageable during a failover, it is installed as a separate Helm release outside the Kloudfuse chart rather than using the bundled ingress-nginx.
Disable the Bundled ingress-nginx
Before installing a standalone controller, disable the ingress-nginx controller that is bundled with the Kloudfuse Helm chart. Add the following to your custom-values.yaml:
ingress-nginx:
enabled: false
| Only one ingress controller can be active in a Kloudfuse cluster at a time. If you are using Envoy Gateway instead of ingress-nginx, these values are already set by the Envoy Gateway configuration. See Configure Nginx Ingress for details. |
Configure the Standalone Controller
Create a values.yaml for the ingress-nginx Helm chart. The controller must be pinned to the target AZ’s node group via affinity and tolerations, and assigned a unique ingressClass name so that Kloudfuse resources target the correct controller.
rbac:
scope: false
controller:
resources:
requests:
cpu: 10000m
memory: 15000Mi
scope:
enabled: false
containerName: nginx-controller
allowSnippetAnnotations: false
config:
client-header-buffer-size: "16k"
large-client-header-buffers: "4 16k"
proxy-buffer-size: "64k"
proxy-buffers: "8 64k"
proxy-busy-buffers-size: "128k"
location-snippet: |
if ($request_uri = /) {
add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0';
expires off;
}
if ($request_uri ~* \.(?:html|js|css|gif|jpe?g|png)) {
add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0';
expires off;
}
addHeaders:
X-Content-Type-Options: "nosniff"
X-Frame-Options: "SAMEORIGIN"
Content-Security-Policy: "default-src 'self' https://*.jsdelivr.net/ https://fonts.googleapis.com/ https://apis.google.com/js/ https://fonts.gstatic.com/ 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:;"
Strict-Transport-Security: "max-age=31536000; includeSubDomains"
metrics:
enabled: true
extraArgs:
enable-metrics: true
podAnnotations:
prometheus.io/path: /metrics
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
ingressClassResource:
enabled: true
name: <az-name> (1)
ingressClass: <az-name>
watchIngressWithoutClass: false
externalTrafficPolicy: Local
service:
enableHttp: false
loadBalancerIP: "<EXTERNAL_LB_IP>" (2)
external:
enabled: true
internal:
enabled: true
loadBalancerIP: "<INTERNAL_LB_IP>" (3)
annotations:
networking.gke.io/load-balancer-type: "Internal"
cloud.google.com/load-balancer-type: "Internal"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: ng_label
operator: In
values:
- <az-name>
tolerations:
- key: "ng_taint"
operator: "Equal"
value: "<az-name>"
effect: "NoSchedule"
| 1 | az-name: A short identifier for the AZ (for example, az1 or az2). Used as the ingress class name and node affinity label. Must match the node group labels applied to the AZ’s nodes. |
| 2 | EXTERNAL_LB_IP: The external static IP address for ingest traffic. Map this to your public DNS hostname (for example, observability-ingest.example.com). |
| 3 | INTERNAL_LB_IP: The internal IP address for UI/query traffic. Map this to your internal DNS hostname (for example, observability.example.com). |
Install the Standalone Controller
helm upgrade --install <release-name> ingress-nginx/ingress-nginx \ (1)
--namespace <release-name> --create-namespace \
--version <version> \ (2)
-f values.yaml
| 1 | Replace <release-name> with a name that identifies the AZ (for example, ingress-az1 or ingress-az2). Use the same value for both the release name and namespace so each AZ controller is isolated. |
| 2 | Replace <version> with the ingress-nginx chart version required for your environment. See the ingress-nginx releases page for available versions. |
Repeat this step for each AZ, using a distinct <release-name> and a corresponding values.yaml with the correct AZ-specific settings.