From f0ee67f3edbc3569d08d373cff72158ae060fc7e Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 23 Jan 2026 18:44:18 -0800 Subject: [PATCH] improvement(helm): add internal ingress support and same-host path consolidation (#2960) * improvement(helm): add internal ingress support and same-host path consolidation * improvement(helm): clean up ingress template comments Simplify verbose inline Helm comments and section dividers to match the minimal style used in services.yaml. Co-Authored-By: Claude Opus 4.5 * fix(helm): add missing copilot path consolidation for realtime host When copilot.host equals realtime.host but differs from app.host, copilot paths were not being routed. Added logic to consolidate copilot paths into the realtime rule for this scenario. Co-Authored-By: Claude Opus 4.5 * improvement(helm): follow ingress best practices - Remove orphan comments that appeared when services were disabled - Add documentation about path ordering requirements - Paths rendered in order: realtime, copilot, app (specific before catch-all) - Clean template output matching industry Helm chart standards --------- Co-authored-by: Claude Opus 4.5 --- helm/sim/examples/values-azure.yaml | 39 +++++++-- helm/sim/templates/ingress-internal.yaml | 105 +++++++++++++++++++++++ helm/sim/templates/ingress.yaml | 58 ++++++++++--- helm/sim/values.yaml | 56 +++++++++--- 4 files changed, 228 insertions(+), 30 deletions(-) create mode 100644 helm/sim/templates/ingress-internal.yaml diff --git a/helm/sim/examples/values-azure.yaml b/helm/sim/examples/values-azure.yaml index 1bf8e4f0f..982605fa7 100644 --- a/helm/sim/examples/values-azure.yaml +++ b/helm/sim/examples/values-azure.yaml @@ -172,29 +172,56 @@ ollama: OLLAMA_KEEP_ALIVE: "-1" OLLAMA_DEBUG: "1" -# Ingress configuration (NGINX ingress controller on Azure AKS) +# Ingress configuration ingress: enabled: true className: nginx - + annotations: nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - + # Main application app: host: simstudio.acme.com paths: - path: / pathType: Prefix - + # Realtime service realtime: host: simstudio-ws.acme.com paths: - path: / pathType: Prefix - + # TLS configuration tls: enabled: true - secretName: simstudio-tls-secret \ No newline at end of file + secretName: simstudio-tls-secret + +# Internal Ingress configuration +ingressInternal: + enabled: false + className: azure-application-gateway + + annotations: + appgw.ingress.kubernetes.io/use-private-ip: "true" + + # Main application + app: + host: simstudio-internal.acme.local + paths: + - path: / + pathType: Prefix + + # Realtime service + realtime: + host: simstudio-internal.acme.local + paths: + - path: /socket.io + pathType: Prefix + + # TLS configuration + tls: + enabled: true + secretName: simstudio-internal-tls-secret \ No newline at end of file diff --git a/helm/sim/templates/ingress-internal.yaml b/helm/sim/templates/ingress-internal.yaml new file mode 100644 index 000000000..9cceb6d64 --- /dev/null +++ b/helm/sim/templates/ingress-internal.yaml @@ -0,0 +1,105 @@ +{{- if .Values.ingressInternal.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "sim.fullname" . }}-ingress-internal + namespace: {{ .Release.Namespace }} + labels: + {{- include "sim.labels" . | nindent 4 }} + {{- with .Values.ingressInternal.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingressInternal.className }} + ingressClassName: {{ .Values.ingressInternal.className }} + {{- end }} + {{- if .Values.ingressInternal.tls.enabled }} + tls: + - hosts: + - {{ .Values.ingressInternal.app.host | quote }} + {{- if and .Values.realtime.enabled (ne .Values.ingressInternal.realtime.host .Values.ingressInternal.app.host) }} + - {{ .Values.ingressInternal.realtime.host | quote }} + {{- end }} + {{- if and .Values.copilot.enabled .Values.ingressInternal.copilot }} + {{- if and (ne .Values.ingressInternal.copilot.host .Values.ingressInternal.app.host) (ne .Values.ingressInternal.copilot.host .Values.ingressInternal.realtime.host) }} + - {{ .Values.ingressInternal.copilot.host | quote }} + {{- end }} + {{- end }} + secretName: {{ .Values.ingressInternal.tls.secretName }} + {{- end }} + rules: + - host: {{ .Values.ingressInternal.app.host | quote }} + http: + paths: + {{- if and .Values.realtime.enabled (eq .Values.ingressInternal.realtime.host .Values.ingressInternal.app.host) }} + {{- range .Values.ingressInternal.realtime.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-realtime + port: + number: {{ $.Values.realtime.service.port }} + {{- end }} + {{- end }} + {{- if and .Values.copilot.enabled .Values.ingressInternal.copilot (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.app.host) }} + {{- range .Values.ingressInternal.copilot.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-copilot + port: + number: {{ $.Values.copilot.server.service.port }} + {{- end }} + {{- end }} + {{- range .Values.ingressInternal.app.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-app + port: + number: {{ $.Values.app.service.port }} + {{- end }} + {{- if and .Values.realtime.enabled (ne .Values.ingressInternal.realtime.host .Values.ingressInternal.app.host) }} + - host: {{ .Values.ingressInternal.realtime.host | quote }} + http: + paths: + {{- range .Values.ingressInternal.realtime.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-realtime + port: + number: {{ $.Values.realtime.service.port }} + {{- end }} + {{- if and .Values.copilot.enabled .Values.ingressInternal.copilot (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.realtime.host) }} + {{- range .Values.ingressInternal.copilot.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-copilot + port: + number: {{ $.Values.copilot.server.service.port }} + {{- end }} + {{- end }} + {{- end }} + {{- if and .Values.copilot.enabled .Values.ingressInternal.copilot (and (ne .Values.ingressInternal.copilot.host .Values.ingressInternal.app.host) (ne .Values.ingressInternal.copilot.host .Values.ingressInternal.realtime.host)) }} + - host: {{ .Values.ingressInternal.copilot.host | quote }} + http: + paths: + {{- range .Values.ingressInternal.copilot.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-copilot + port: + number: {{ $.Values.copilot.server.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/sim/templates/ingress.yaml b/helm/sim/templates/ingress.yaml index 798114122..1a327101a 100644 --- a/helm/sim/templates/ingress.yaml +++ b/helm/sim/templates/ingress.yaml @@ -17,20 +17,43 @@ spec: {{- if .Values.ingress.tls.enabled }} tls: - hosts: - - {{ .Values.ingress.app.host }} - {{- if .Values.realtime.enabled }} - - {{ .Values.ingress.realtime.host }} + - {{ .Values.ingress.app.host | quote }} + {{- if and .Values.realtime.enabled (ne .Values.ingress.realtime.host .Values.ingress.app.host) }} + - {{ .Values.ingress.realtime.host | quote }} {{- end }} {{- if and .Values.copilot.enabled .Values.ingress.copilot }} - - {{ .Values.ingress.copilot.host }} + {{- if and (ne .Values.ingress.copilot.host .Values.ingress.app.host) (ne .Values.ingress.copilot.host .Values.ingress.realtime.host) }} + - {{ .Values.ingress.copilot.host | quote }} + {{- end }} {{- end }} secretName: {{ .Values.ingress.tls.secretName }} {{- end }} rules: - # Main application ingress rule - - host: {{ .Values.ingress.app.host }} + - host: {{ .Values.ingress.app.host | quote }} http: paths: + {{- if and .Values.realtime.enabled (eq .Values.ingress.realtime.host .Values.ingress.app.host) }} + {{- range .Values.ingress.realtime.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-realtime + port: + number: {{ $.Values.realtime.service.port }} + {{- end }} + {{- end }} + {{- if and .Values.copilot.enabled .Values.ingress.copilot (eq .Values.ingress.copilot.host .Values.ingress.app.host) }} + {{- range .Values.ingress.copilot.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-copilot + port: + number: {{ $.Values.copilot.server.service.port }} + {{- end }} + {{- end }} {{- range .Values.ingress.app.paths }} - path: {{ .path }} pathType: {{ .pathType }} @@ -40,9 +63,8 @@ spec: port: number: {{ $.Values.app.service.port }} {{- end }} - {{- if .Values.realtime.enabled }} - # Realtime service ingress rule - - host: {{ .Values.ingress.realtime.host }} + {{- if and .Values.realtime.enabled (ne .Values.ingress.realtime.host .Values.ingress.app.host) }} + - host: {{ .Values.ingress.realtime.host | quote }} http: paths: {{- range .Values.ingress.realtime.paths }} @@ -54,10 +76,20 @@ spec: port: number: {{ $.Values.realtime.service.port }} {{- end }} + {{- if and .Values.copilot.enabled .Values.ingress.copilot (eq .Values.ingress.copilot.host .Values.ingress.realtime.host) }} + {{- range .Values.ingress.copilot.paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "sim.fullname" $ }}-copilot + port: + number: {{ $.Values.copilot.server.service.port }} + {{- end }} + {{- end }} {{- end }} - {{- if and .Values.copilot.enabled .Values.ingress.copilot }} - # Copilot service ingress rule - - host: {{ .Values.ingress.copilot.host }} + {{- if and .Values.copilot.enabled .Values.ingress.copilot (and (ne .Values.ingress.copilot.host .Values.ingress.app.host) (ne .Values.ingress.copilot.host .Values.ingress.realtime.host)) }} + - host: {{ .Values.ingress.copilot.host | quote }} http: paths: {{- range .Values.ingress.copilot.paths }} @@ -70,4 +102,4 @@ spec: number: {{ $.Values.copilot.server.service.port }} {{- end }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/helm/sim/values.yaml b/helm/sim/values.yaml index 92db160df..c182c2772 100644 --- a/helm/sim/values.yaml +++ b/helm/sim/values.yaml @@ -552,36 +552,70 @@ ollama: extraVolumeMounts: [] # Ingress configuration +# When services share the same host, paths are consolidated into a single rule. +# Path order: realtime paths, copilot paths, then app paths (most specific first). +# Ensure specific paths (e.g., /socket.io, /copilot) come before catch-all paths (/). ingress: - # Enable/disable ingress enabled: false - - # Ingress class name className: nginx - - # Annotations + annotations: nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - - # Main application host configuration + + # Main application (use / as catch-all) app: host: sim.local paths: - path: / pathType: Prefix - - # Realtime service host configuration + + # Realtime service (use /socket.io when sharing host with app) realtime: host: sim-ws.local paths: - path: / pathType: Prefix - - # TLS configuration + + # Copilot service (optional, use /copilot when sharing host) + # copilot: + # host: sim.local + # paths: + # - path: /copilot + # pathType: Prefix + tls: enabled: false secretName: sim-tls-secret +# Internal Ingress configuration +# Same path ordering rules apply as above. +ingressInternal: + enabled: false + className: nginx + annotations: {} + + app: + host: sim-internal.local + paths: + - path: / + pathType: Prefix + + realtime: + host: sim-internal.local + paths: + - path: /socket.io + pathType: Prefix + + # copilot: + # host: sim-internal.local + # paths: + # - path: /copilot + # pathType: Prefix + + tls: + enabled: false + secretName: sim-internal-tls-secret + # Service Account configuration serviceAccount: # Specifies whether a service account should be created