diff --git a/apps/appsets/project-understack-infra.yaml b/apps/appsets/project-understack-infra.yaml index 1cb5e1d4c..1b84ddecd 100644 --- a/apps/appsets/project-understack-infra.yaml +++ b/apps/appsets/project-understack-infra.yaml @@ -15,6 +15,8 @@ spec: server: '*' - namespace: 'cilium' server: '*' + - namespace: 'envoy-gateway' + server: '*' - namespace: 'kube-system' server: '*' clusterResourceWhitelist: diff --git a/apps/appsets/project-understack.yaml b/apps/appsets/project-understack.yaml index d588c7f2a..7eb52f42a 100644 --- a/apps/appsets/project-understack.yaml +++ b/apps/appsets/project-understack.yaml @@ -11,6 +11,8 @@ spec: destinations: - namespace: 'argo' server: '*' + - namespace: 'argocd' + server: '*' - namespace: 'argo-events' server: '*' - namespace: 'cert-manager' @@ -29,6 +31,8 @@ spec: server: '*' - namespace: 'kube-system' server: '*' + - namespace: 'envoy-gateway' + server: '*' clusterResourceWhitelist: - group: '*' kind: '*' diff --git a/apps/infra/cert-manager.yaml b/apps/infra/cert-manager.yaml index 671eaf0db..470f80b1d 100644 --- a/apps/infra/cert-manager.yaml +++ b/apps/infra/cert-manager.yaml @@ -3,9 +3,13 @@ component: cert-manager sources: - repoURL: https://charts.jetstack.io chart: cert-manager - targetRevision: '1.18.2' + targetRevision: '1.19.2' helm: releaseName: cert-manager valuesObject: crds: enabled: true + config: + enableGatewayAPI: true + apiVersion: controller.config.cert-manager.io/v1alpha1 + kind: ControllerConfiguration diff --git a/apps/infra/envoy-gateway.yaml b/apps/infra/envoy-gateway.yaml new file mode 100644 index 000000000..fd4f70c1b --- /dev/null +++ b/apps/infra/envoy-gateway.yaml @@ -0,0 +1,17 @@ +--- +component: envoy-gateway +sources: + - repoURL: docker.io/envoyproxy + chart: gateway-helm + path: gateway-helm + targetRevision: v1.6.0 + helm: + releaseName: envoy-gateway + valueFiles: + - $understack/components/envoy-gateway/values.yaml + - $deploy/{{.name}}/helm-configs/envoy-gateway.yaml + ignoreMissingValueFiles: true + - ref: understack + path: 'components/envoy-gateway' + - ref: deploy + path: '{{.name}}/manifests/envoy-gateway' diff --git a/apps/operators/external-dns.yaml b/apps/operators/external-dns.yaml index df8cc919d..505a2a770 100644 --- a/apps/operators/external-dns.yaml +++ b/apps/operators/external-dns.yaml @@ -3,7 +3,7 @@ component: external-dns sources: - repoURL: ghcr.io/rackerlabs/charts chart: external-dns-rackspace - targetRevision: 0.1.0 + targetRevision: 0.2.0 helm: releaseName: external-dns-rackspace namespace: "external-dns" diff --git a/apps/site/envoy-configs.yaml b/apps/site/envoy-configs.yaml new file mode 100644 index 000000000..e4531a0cc --- /dev/null +++ b/apps/site/envoy-configs.yaml @@ -0,0 +1,14 @@ +--- +component: envoy-configs +componentNamespace: envoy-gateway +sources: + - ref: understack + path: components/envoy-configs + helm: + releaseName: envoy-configs + valueFiles: + - $understack/components/envoy-configs/values.yaml + - $deploy/{{.name}}/helm-configs/envoy-configs.yaml + ignoreMissingValueFiles: true + - ref: deploy + path: '{{.name}}/manifests/envoy-configs' diff --git a/bootstrap/bootstrap.sh b/bootstrap/bootstrap.sh index 9567d8586..a88388d25 100755 --- a/bootstrap/bootstrap.sh +++ b/bootstrap/bootstrap.sh @@ -19,7 +19,36 @@ wait_for_cert_manager() { echo " done." } -kubectl kustomize --enable-helm bootstrap/cert-manager/ | kubectl apply --server-side -f - +check_required_binaries() { + local missing_binaries=() + + if ! command -v kubectl &>/dev/null; then + missing_binaries+=("kubectl") + fi + + if ! command -v helm &>/dev/null; then + missing_binaries+=("helm") + fi + + if [ ${#missing_binaries[@]} -ne 0 ]; then + echo "Error: Required binaries not found: ${missing_binaries[*]}" + exit 1 + fi +} + +check_required_binaries + +CM_CHART_VERSION=v1.19.2 +helm upgrade --install \ + cert-manager oci://quay.io/jetstack/charts/cert-manager:${CM_CHART_VERSION} \ + --create-namespace \ + --namespace cert-manager \ + --set crds.enabled=true \ + --set config.enableGatewayApi=true \ + --set config.apiVersion="controller.config.cert-manager.io/v1alpha1" \ + --set config.kind="ControllerConfiguration" \ + cert-manager + wait_for_cert_manager kubectl kustomize --enable-helm bootstrap | kubectl apply --server-side -f - kubectl apply -f bootstrap/cert-manager/issuer-kube-system-self-signed.yaml diff --git a/bootstrap/cert-manager/kustomization.yaml b/bootstrap/cert-manager/kustomization.yaml deleted file mode 100644 index b508499f0..000000000 --- a/bootstrap/cert-manager/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- https://github.com/cert-manager/cert-manager/releases/download/v1.19.2/cert-manager.yaml diff --git a/components/argo-workflows/ingress.yaml b/components/argo-workflows/ingress.yaml deleted file mode 100644 index 7a395d1ce..000000000 --- a/components/argo-workflows/ingress.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - annotations: - cert-manager.io/cluster-issuer: understack-cluster-issuer - nginx.ingress.kubernetes.io/backend-protocol: HTTPS - nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - name: argo-workflows -spec: - ingressClassName: nginx - rules: - - host: workflows.local - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: argo-server - port: - number: 2746 - tls: - - hosts: - - workflows.local - secretName: argo-workflows-ingress-tls diff --git a/components/argocd/values.yaml b/components/argocd/values.yaml index bb5a267f3..109cd051a 100644 --- a/components/argocd/values.yaml +++ b/components/argocd/values.yaml @@ -15,12 +15,7 @@ applicationSet: interval: 30s server: ingress: - enabled: true - ingressClassName: nginx - tls: true - annotations: - nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + enabled: false metrics: enabled: true serviceMonitor: diff --git a/components/cinder/values.yaml b/components/cinder/values.yaml index 73925fdbc..ac097de2b 100644 --- a/components/cinder/values.yaml +++ b/components/cinder/values.yaml @@ -54,12 +54,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - api: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer pod: mounts: @@ -232,6 +226,7 @@ manifests: secret_rabbitmq: false secret_registry: false service_ingress_api: false + ingress_api: false deployment_backup: false # We set the `secret_keystone` and `secret_ks_etc` to false in order to disable # Kubernetes section generation in OpenStack Helm, because we want those diff --git a/components/dex/values.yaml b/components/dex/values.yaml index 62e1f395d..8ceaa923b 100644 --- a/components/dex/values.yaml +++ b/components/dex/values.yaml @@ -115,8 +115,4 @@ envVars: key: client-secret ingress: - enabled: true - className: nginx - annotations: - cert-manager.io/cluster-issuer: understack-cluster-issuer - nginx.ingress.kubernetes.io/backend-protocol: HTTP + enabled: false diff --git a/components/envoy-configs/.helmignore b/components/envoy-configs/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/components/envoy-configs/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/components/envoy-configs/Chart.yaml b/components/envoy-configs/Chart.yaml new file mode 100644 index 000000000..0c109e0ac --- /dev/null +++ b/components/envoy-configs/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v2 +name: envoy-configs +description: Chart with configuration for Envoy Gateway +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 1.0.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.6.0" diff --git a/components/envoy-configs/templates/_helpers.tpl b/components/envoy-configs/templates/_helpers.tpl new file mode 100644 index 000000000..1beaaac45 --- /dev/null +++ b/components/envoy-configs/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "envoy-configs.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "envoy-configs.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "envoy-configs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "envoy-configs.labels" -}} +helm.sh/chart: {{ include "envoy-configs.chart" . }} +{{ include "envoy-configs.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "envoy-configs.selectorLabels" -}} +app.kubernetes.io/name: {{ include "envoy-configs.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "envoy-configs.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "envoy-configs.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/components/envoy-configs/templates/gw-external.yaml.tpl b/components/envoy-configs/templates/gw-external.yaml.tpl new file mode 100644 index 000000000..dca86126b --- /dev/null +++ b/components/envoy-configs/templates/gw-external.yaml.tpl @@ -0,0 +1,78 @@ +{{- if .Values.gateways.external }} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: {{ .Values.gateways.external.name }} + namespace: {{ .Values.gateways.external.namespace }} + annotations: + cert-manager.io/cluster-issuer: {{ .Values.gateways.external.issuer | default "understack-cluster-issuer"}} + labels: + {{- include "envoy-configs.labels" . | nindent 4 }} +spec: + gatewayClassName: {{ .Values.gateways.external.className }} + listeners: + {{- range .Values.routes.http }} + {{- $listenerName := .name | default (index (splitList "." .fqdn) 0) }} + - name: {{ $listenerName }} + port: {{ $.Values.gateways.external.port | default 443 }} + protocol: HTTPS + hostname: {{ .fqdn }} + tls: + mode: Terminate + certificateRefs: + - name: {{ $listenerName }}-tls + allowedRoutes: + namespaces: + {{- if .selector }} + from: Selector + selector: + {{- .selector | toYaml | nindent 12 }} + {{- else }} + from: {{ .from | default "All" }} + {{- end }} + {{- end }} + {{- range .Values.routes.tls }} + {{- $listenerName := .name | default (index (splitList "." .fqdn) 0) }} + - name: {{ $listenerName }} + port: {{ $.Values.gateways.external.port | default 443 }} + protocol: TLS + hostname: {{ .fqdn | quote }} + tls: + mode: Passthrough + certificateRefs: + - name: {{ $listenerName }}-tls + allowedRoutes: + namespaces: + {{- if .selector }} + from: Selector + selector: + {{- .selector | toYaml | nindent 12 }} + {{- else }} + from: {{ .from | default "All" }} + {{- end }} + {{- end }} + {{- if .Values.gateways.external.serviceAnnotations }} + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: {{ .Values.gateways.external.name }}-proxy + {{- end }} +{{- if .Values.gateways.external.serviceAnnotations }} +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: {{ .Values.gateways.external.name }}-proxy + namespace: {{ .Values.gateways.external.namespace }} +spec: + provider: + type: Kubernetes + kubernetes: + envoyService: + annotations: + {{- .Values.gateways.external.serviceAnnotations | toYaml | nindent 10 }} + externalTrafficPolicy: {{ .Values.gateways.external.externalTrafficPolicy | default "Cluster" }} +{{- end }} +{{- end }} diff --git a/components/envoy-configs/templates/gw-internal.yaml.tpl b/components/envoy-configs/templates/gw-internal.yaml.tpl new file mode 100644 index 000000000..a5f4785f8 --- /dev/null +++ b/components/envoy-configs/templates/gw-internal.yaml.tpl @@ -0,0 +1,40 @@ +{{- if .Values.gateways.internal }} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: {{ .Values.gateways.internal.name }} + namespace: {{ .Values.gateways.internal.namespace }} +spec: + gatewayClassName: {{ .Values.gateways.internal.className }} + listeners: + - name: http + protocol: HTTP + port: {{ .Values.gateways.internal.port | default 80 }} + allowedRoutes: + namespaces: + from: All + {{- if .Values.gateways.internal.serviceAnnotations }} + infrastructure: + parametersRef: + group: gateway.envoyproxy.io + kind: EnvoyProxy + name: {{ .Values.gateways.internal.name }}-proxy + {{- end }} +{{- if .Values.gateways.internal.serviceAnnotations }} +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyProxy +metadata: + name: {{ .Values.gateways.internal.name }}-proxy + namespace: {{ .Values.gateways.internal.namespace }} +spec: + provider: + type: Kubernetes + kubernetes: + envoyService: + annotations: + {{- .Values.gateways.internal.serviceAnnotations | toYaml | nindent 10 }} + externalTrafficPolicy: {{ .Values.gateways.internal.externalTrafficPolicy | default "Cluster" }} +{{- end }} +{{- end }} diff --git a/components/envoy-configs/templates/httproute.yaml.tpl b/components/envoy-configs/templates/httproute.yaml.tpl new file mode 100644 index 000000000..4622a75d5 --- /dev/null +++ b/components/envoy-configs/templates/httproute.yaml.tpl @@ -0,0 +1,60 @@ +{{- range .Values.routes.http }} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + {{- if .name }} + name: {{ .name }} + {{- else }} + {{- $name := index (splitList "." .fqdn) 0 }} + name: {{ $name }} + {{- end }} + namespace: {{ .namespace | default "openstack" }} + labels: + {{- include "envoy-configs.labels" $ | nindent 4 }} +spec: + parentRefs: + - name: {{ $.Values.gateways.external.name }} + namespace: {{ $.Values.gateways.external.namespace }} + hostnames: [{{ .fqdn | quote }}] + rules: + - matches: + - path: + type: {{ .pathType | default "PathPrefix" }} + value: {{ .path | default "/" }} + {{- with .filters }} + filters: + {{- toYaml . | nindent 8 }} + {{- end }} + backendRefs: + {{- if eq .service.backendType "tls" }} + - name: {{ .service.name }} + group: gateway.envoyproxy.io + kind: Backend + {{- with .namespace }} + namespace: {{ . }} + {{- end }} + {{- else }} + - name: {{ .service.name }} + {{- with .namespace }} + namespace: {{ . }} + {{- end }} + port: {{ .service.port }} + {{- end }} +{{- if eq .service.backendType "tls" }} +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: Backend +metadata: + name: {{ .service.name }} + namespace: {{ .namespace | default "openstack" }} +spec: + endpoints: + - fqdn: + # standard in-cluster DNS name + hostname: {{ .service.name }}.{{ .namespace }}.svc.cluster.local + port: {{ .service.port }} + tls: + insecureSkipVerify: true +{{- end }} +{{- end }} diff --git a/components/envoy-configs/templates/tlsroute.yaml.tpl b/components/envoy-configs/templates/tlsroute.yaml.tpl new file mode 100644 index 000000000..66a03f36a --- /dev/null +++ b/components/envoy-configs/templates/tlsroute.yaml.tpl @@ -0,0 +1,25 @@ +{{- range .Values.routes.tls }} +--- +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TLSRoute +metadata: + {{- if .name }} + name: {{ .name }} + {{- else }} + {{- $name := index (splitList "." .fqdn) 0 }} + name: {{ $name }} + {{- end }} + namespace: {{ .namespace | default "envoy-gateway" }} +spec: + parentRefs: + - name: {{ $.Values.gateways.external.name }} + namespace: {{ $.Values.gateways.external.namespace }} + hostnames: [{{ .fqdn | quote }}] + rules: + - backendRefs: + - name: {{ .service.name }} + {{- with .namespace }} + namespace: {{ . }} + {{- end }} + port: {{ .service.port }} +{{- end }} diff --git a/components/envoy-configs/values.schema.json b/components/envoy-configs/values.schema.json new file mode 100644 index 000000000..f7bbc099d --- /dev/null +++ b/components/envoy-configs/values.schema.json @@ -0,0 +1,215 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "envoy-configs Helm Chart Values", + "description": "Schema for envoy-configs component values.yaml configuration", + "type": "object", + "properties": { + "gateways": { + "type": "object", + "description": "Gateway configurations for external and internal access", + "properties": { + "external": { + "type": "object", + "description": "External gateway configuration", + "properties": { + "name": { + "type": "string", + "description": "Name of the external gateway" + }, + "namespace": { + "type": "string", + "description": "Namespace where the external gateway is deployed" + }, + "className": { + "type": "string", + "description": "Gateway class name (e.g., cilium)" + }, + "serviceAnnotations": { + "type": "object", + "description": "Annotations to be placed on the Service generated for this gateway" + } + }, + "required": [ + "name", + "namespace", + "className" + ], + "additionalProperties": false + }, + "internal": { + "type": "object", + "description": "Internal gateway configuration", + "properties": { + "name": { + "type": "string", + "description": "Name of the internal gateway" + }, + "namespace": { + "type": "string", + "description": "Namespace where the internal gateway is deployed" + }, + "className": { + "type": "string", + "description": "Gateway class name (e.g., cilium)" + }, + "serviceAnnotations": { + "type": "object", + "description": "Annotations to be placed on the Service generated for this gateway" + } + }, + "required": [ + "name", + "namespace", + "className" + ], + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "routes": { + "type": "object", + "description": "HTTP and TLS routes configurations for Understack services", + "properties": { + "http": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "description": "Fully qualified domain name for the route" + }, + "name": { + "type": "string", + "description": "Name identifier for the route. If not defined, first part of fqdn is used." + }, + "namespace": { + "type": "string", + "description": "Namespace where the httproute will be installed (same as backend service)" + }, + "service": { + "type": "object", + "description": "Kubernetes service backend configuration for the route", + "properties": { + "name": { + "type": "string", + "description": "Name of the Kubernetes service" + }, + "port": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "Numeric port of the service (not target port)" + }, + "backendType": { + "type": "string", + "description": "Type of traffic that service expects - 'http' or 'tls'", + "enum": ["tls", "http"] + } + }, + "required": [ + "name", + "port" + ], + "additionalProperties": false + }, + "selector": { + "type": "object", + "description": "Kubernetes-style label selector (key-value pairs)", + "additionalProperties": { + "type": "string" + } + }, + "from": { + "type": "string", + "enum": [ + "Same", + "All", + "Selector" + ], + "description": "Specifies where traffic can originate from" + }, + "filters": { + "type": "object", + "description": "Route filters." + } + }, + "required": [ + "fqdn", + "service" + ], + "additionalProperties": false + } + }, + "tls": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "description": "Fully qualified domain name for the route" + }, + "name": { + "type": "string", + "description": "Name identifier for the route. If not defined, first part of fqdn is used." + }, + "namespace": { + "type": "string", + "description": "Namespace where the httproute will be installed (same as backend service)" + }, + "service": { + "type": "object", + "description": "Kubernetes service backend configuration for the route", + "properties": { + "name": { + "type": "string", + "description": "Name of the Kubernetes service" + }, + "port": { + "type": "integer", + "minimum": 1, + "maximum": 65535, + "description": "Numeric port of the service (not target port)" + } + }, + "required": [ + "name", + "port" + ], + "additionalProperties": false + }, + "selector": { + "type": "object", + "description": "Kubernetes-style label selector (key-value pairs)", + "additionalProperties": { + "type": "string" + } + }, + "from": { + "type": "string", + "enum": [ + "Same", + "All", + "Selector" + ], + "description": "Specifies where traffic can originate from" + } + }, + "required": [ + "fqdn", + "service" + ], + "additionalProperties": false + } + } + } + } + }, + "required": [ + "gateways", + "routes" + ], + "additionalProperties": false +} diff --git a/components/envoy-configs/values.yaml b/components/envoy-configs/values.yaml new file mode 100644 index 000000000..17de1ac18 --- /dev/null +++ b/components/envoy-configs/values.yaml @@ -0,0 +1,4 @@ +gateways: {} +routes: + http: [] + tls: [] diff --git a/components/envoy-gateway/README.md b/components/envoy-gateway/README.md new file mode 100644 index 000000000..0182bc0cf --- /dev/null +++ b/components/envoy-gateway/README.md @@ -0,0 +1,4 @@ +# envoy-gateway + +This component covers installation of the Envoy Gateway and it's related CRDs. +It does not include actual configs (see `envoy-configs` for that). diff --git a/components/envoy-gateway/values.yaml b/components/envoy-gateway/values.yaml new file mode 100644 index 000000000..a07220a1c --- /dev/null +++ b/components/envoy-gateway/values.yaml @@ -0,0 +1,14 @@ +deployment: + envoyGateway: + resources: + limits: + cpu: 3000m + memory: 4096Mi +config: + envoyGateway: + extensionApis: + enableBackend: true + enableEnvoyPatchPolicy: true + logging: + level: + default: info diff --git a/components/glance/values.yaml b/components/glance/values.yaml index 71e389fee..ce69b21bb 100644 --- a/components/glance/values.yaml +++ b/components/glance/values.yaml @@ -30,12 +30,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - api: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer # Glance storage backend # we'll switch to radosgw in the future @@ -137,6 +131,7 @@ manifests: pod_rally_test: false secret_db: false service_ingress_api: false + ingress_api: false # We set the `secret_keystone` and `secret_ks_etc` to false in order to disable # Kubernetes section generation in OpenStack Helm, because we want those # to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled diff --git a/components/horizon/values.yaml b/components/horizon/values.yaml index 6bb2b2ae7..e62721c48 100644 --- a/components/horizon/values.yaml +++ b/components/horizon/values.yaml @@ -48,12 +48,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - dashboard: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer # (nicholas.kuechler) updating the jobs list to remove the 'horizon-db-init' job. dependencies: @@ -69,6 +63,7 @@ manifests: job_db_init: false secret_db: false service_ingress: false + ingress_api: false pod: lifecycle: diff --git a/components/ironic/values.yaml b/components/ironic/values.yaml index 7491aafdd..b0357f2ab 100644 --- a/components/ironic/values.yaml +++ b/components/ironic/values.yaml @@ -136,15 +136,6 @@ secrets: network: api: - ingress: - public: true - classes: - namespace: "nginx" - cluster: "nginx-openstack" - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer external_policy_local: false node_port: enabled: false @@ -200,6 +191,8 @@ manifests: secret_rabbitmq: false secret_registry: false service_ingress_api: false + service_ingress: false + ingress_api: false # We set the `secret_keystone` and `secret_ks_etc` to false in order to disable # Kubernetes section generation in OpenStack Helm, because we want those # to be generated indirectly via ESO as configured in keystoneServiceUsers.enabled diff --git a/components/keystone/values.yaml b/components/keystone/values.yaml index a14995945..cf9f2508d 100644 --- a/components/keystone/values.yaml +++ b/components/keystone/values.yaml @@ -13,12 +13,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - api: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer dependencies: static: @@ -340,6 +334,7 @@ manifests: # that is later consumed via components/openstack helm chart secret_keystone: false secret_ks_etc: false + ingress_api: false annotations: # we need to modify the annotations on OpenStack Helm diff --git a/components/nautobot/values.yaml b/components/nautobot/values.yaml index f5b9ad4c2..6f57ab232 100644 --- a/components/nautobot/values.yaml +++ b/components/nautobot/values.yaml @@ -86,13 +86,7 @@ redis: argocd.argoproj.io/sync-options: Delete=false ingress: - enabled: true - ingressClassName: "nginx" - tls: true - secretName: "nautobot-ingress-tls" - annotations: - cert-manager.io/cluster-issuer: understack-cluster-issuer - nginx.ingress.kubernetes.io/backend-protocol: HTTPS + enabled: false # (nicholas.kuechler) seeing something unexpected: # https://networktocode.slack.com/archives/C01NWPK6WHL/p1736445485521569 diff --git a/components/neutron/values.yaml b/components/neutron/values.yaml index 7b805d5e9..f31b44c52 100644 --- a/components/neutron/values.yaml +++ b/components/neutron/values.yaml @@ -37,12 +37,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - server: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer conf: plugins: @@ -248,6 +242,7 @@ manifests: # hardcodes the config-file flag which then causes oslo.config to prefer # that data over the directory which we want to override configmap_bin: false + ingress_server: false annotations: # we need to modify the annotations on OpenStack Helm diff --git a/components/nova/values.yaml b/components/nova/values.yaml index 73a9d0c5d..19e5bf906 100644 --- a/components/nova/values.yaml +++ b/components/nova/values.yaml @@ -41,12 +41,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - osapi: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer conf: ceph: @@ -227,6 +221,11 @@ manifests: # that is later consumed via components/openstack helm chart secret_keystone: false secret_ks_etc: false + ingress_metadata: false + ingress_novncproxy: false + ingress_serialproxy: false + ingress_spiceproxy: false + ingress_osapi: false annotations: # we need to modify the annotations on OpenStack Helm diff --git a/components/octavia/values.yaml b/components/octavia/values.yaml index ecc88c691..ee648dcaa 100644 --- a/components/octavia/values.yaml +++ b/components/octavia/values.yaml @@ -30,11 +30,6 @@ network: # by OpenStack Helm use_external_ingress_controller: true api: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer external_policy_local: false node_port: enabled: false @@ -167,6 +162,7 @@ manifests: # that is later consumed via components/openstack helm chart secret_keystone: false secret_ks_etc: false + ingress_api: false annotations: # we need to modify the annotations on OpenStack Helm diff --git a/components/openstack/values.schema.json b/components/openstack/values.schema.json index 4b3136bec..8069f21c1 100644 --- a/components/openstack/values.schema.json +++ b/components/openstack/values.schema.json @@ -40,7 +40,10 @@ "description": "Whether to generate the password if it doesn't exist" } }, - "required": ["name", "key"], + "required": [ + "name", + "key" + ], "additionalProperties": false }, "storage": { @@ -72,7 +75,11 @@ "type": "array", "items": { "type": "string", - "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany"] + "enum": [ + "ReadWriteOnce", + "ReadOnlyMany", + "ReadWriteMany" + ] }, "description": "Access modes for the volume" }, @@ -132,11 +139,16 @@ "description": "Enable Kubernetes authentication for the agent" } }, - "required": ["enabled"], + "required": [ + "enabled" + ], "additionalProperties": true } }, - "required": ["port", "kubernetesAuth"], + "required": [ + "port", + "kubernetesAuth" + ], "additionalProperties": true }, "recovery": { @@ -157,7 +169,11 @@ "description": "Cluster bootstrap timeout duration (e.g., '10m')" } }, - "required": ["enabled", "clusterHealthyTimeout", "clusterBootstrapTimeout"], + "required": [ + "enabled", + "clusterHealthyTimeout", + "clusterBootstrapTimeout" + ], "additionalProperties": true }, "config": { @@ -188,11 +204,15 @@ "description": "Storage request size" } }, - "required": ["storage"], + "required": [ + "storage" + ], "additionalProperties": true } }, - "required": ["requests"], + "required": [ + "requests" + ], "additionalProperties": true }, "storageClassName": { @@ -200,17 +220,27 @@ "description": "Storage class name for the volume claim" } }, - "required": ["accessModes", "resources"], + "required": [ + "accessModes", + "resources" + ], "additionalProperties": true } }, - "required": ["reuseStorageVolume", "volumeClaimTemplate"], + "required": [ + "reuseStorageVolume", + "volumeClaimTemplate" + ], "additionalProperties": true } }, "required": [ - "enabled", "sst", "replicaThreads", "agent", - "recovery", "config" + "enabled", + "sst", + "replicaThreads", + "agent", + "recovery", + "config" ], "additionalProperties": true }, @@ -248,7 +278,10 @@ "properties": { "kind": { "type": "string", - "enum": ["ClusterSecretStore", "SecretStore"], + "enum": [ + "ClusterSecretStore", + "SecretStore" + ], "description": "Type of secret store - ClusterSecretStore or SecretStore for namespaced" }, "name": { @@ -256,7 +289,10 @@ "description": "Name of the ClusterSecretStore or SecretStore to use" } }, - "required": ["kind", "name"], + "required": [ + "kind", + "name" + ], "additionalProperties": false }, "externalLinkAnnotationTemplate": { @@ -341,11 +377,16 @@ "additionalProperties": true } }, - "required": ["apiVersion", "kind"], + "required": [ + "apiVersion", + "kind" + ], "additionalProperties": true } } }, - "required": ["regionName"], + "required": [ + "regionName" + ], "additionalProperties": false } diff --git a/components/placement/values.yaml b/components/placement/values.yaml index ffcf767d0..2037f8045 100644 --- a/components/placement/values.yaml +++ b/components/placement/values.yaml @@ -6,12 +6,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - api: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer # (nicholas.kuechler) updating the jobs list to remove the 'placement-db-init' job. dependencies: @@ -83,6 +77,7 @@ manifests: # that is later consumed via components/openstack helm chart secret_keystone: false secret_ks_etc: false + ingress: false annotations: # we need to modify the annotations on OpenStack Helm diff --git a/components/skyline/values.yaml b/components/skyline/values.yaml index ca27c9bf6..97a0d1609 100644 --- a/components/skyline/values.yaml +++ b/components/skyline/values.yaml @@ -14,12 +14,6 @@ network: # instead of expecting the ingress controller provided # by OpenStack Helm use_external_ingress_controller: true - skyline: - ingress: - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # set our default issuer - cert-manager.io/cluster-issuer: understack-cluster-issuer # (nicholas.kuechler) updating the jobs list to remove the 'skyline-db-init' job. dependencies: @@ -41,6 +35,7 @@ manifests: # that is later consumed via components/openstack helm chart secret_keystone: false secret_ks_etc: false + ingress: false pod: mounts: diff --git a/docs/operator-guide/gateway-api.md b/docs/operator-guide/gateway-api.md new file mode 100644 index 000000000..5a95d6249 --- /dev/null +++ b/docs/operator-guide/gateway-api.md @@ -0,0 +1,524 @@ +# Gateway API Migration Guide + +## Overview & Rationale + +UnderStack has migrated from the legacy Ingress API with ingress-nginx controller to the new Kubernetes Gateway API with Envoy Gateway. This migration was driven by the [ingress-nginx project retirement announcement](https://www.kubernetes.dev/blog/2025/11/12/ingress-nginx-retirement/) with a deadline of March 2026. The Kubernetes community recommends migrating to the Gateway API as the modern, standardized approach for managing ingress traffic. + +### Benefits of Gateway API + +- **Role-oriented design**: Separates concerns between cluster operators (Gateway) and application developers (Routes) +- **Expressive routing**: More powerful matching and filtering capabilities +- **Protocol support**: Native support for HTTP, HTTPS, TLS passthrough, TCP, and UDP +- **Extensibility**: Vendor-specific features through policy attachments +- **Type safety**: Strongly typed API with better validation + +## Architecture Overview + +UnderStack uses a centralized Gateway architecture where cluster operators manage shared Gateway resources, and application teams create Route resources in their own namespaces. + +```mermaid +graph TB + subgraph "Cluster Infrastructure (envoy-gateway namespace)" + EGC[Envoy Gateway Controller] + GWE[Gateway: external] + GWI[Gateway: internal] + EGC --> GWE + EGC --> GWI + end + + subgraph "Application Namespaces" + subgraph "openstack namespace" + HR1[HTTPRoute: keystone] + HR2[HTTPRoute: horizon] + HR3[HTTPRoute: nova] + SVC1[Service: keystone-api] + SVC2[Service: horizon] + SVC3[Service: nova-api] + HR1 --> SVC1 + HR2 --> SVC2 + HR3 --> SVC3 + end + + subgraph "argo namespace" + HR4[HTTPRoute: argo-workflows] + SVC4[Service: argo-server] + HR4 --> SVC4 + end + end + + HR1 -.references.-> GWE + HR2 -.references.-> GWE + HR3 -.references.-> GWE + HR4 -.references.-> GWE + + Internet((Internet)) --> GWE + InternalTraffic((Internal)) --> GWI +``` + +## Concept Mapping + +Understanding how Ingress concepts map to Gateway API helps with migration and troubleshooting: + +| Ingress Concept | Gateway API Concept | Location | Description | +|----------------|---------------------|----------|-------------| +| IngressController (ingress-nginx) | Gateway Controller (Envoy Gateway) | `envoy-gateway` namespace | The controller implementation that manages traffic | +| IngressClass | GatewayClass | Cluster-scoped | Defines which controller handles the Gateway | +| Ingress | Gateway | `envoy-gateway` namespace | Defines listeners (ports, protocols, TLS) - shared cluster resource | +| Ingress rules | HTTPRoute / TLSRoute | Application namespace | Defines routing rules (hostnames, paths, backends) | +| `nginx.ingress.kubernetes.io/backend-protocol` annotation | Backend resource | Application namespace | For TLS backends, uses Envoy Gateway's Backend CRD | +| `cert-manager.io/cluster-issuer` annotation | Gateway annotation | On Gateway resource | Certificate management moved to Gateway level | + +### Key Architectural Differences + +**Ingress (Old)**: + +- Each application creates its own Ingress resource +- Ingress includes both infrastructure concerns (TLS, listeners) and routing rules +- Annotations used heavily for controller-specific features +- Each Ingress can specify its own TLS configuration + +**Gateway API (New)**: + +- Cluster operators create shared Gateway resources (external, internal) +- Applications create lightweight Route resources that reference Gateways +- Clear separation: Gateway = infrastructure, Route = application routing +- TLS certificates managed at Gateway level for all routes +- Routes can be in different namespaces than the Gateway + +## UnderStack Implementation + +### Gateway Resources + +UnderStack deploys two shared Gateways in the `envoy-gateway` namespace: + +**External Gateway** (`gw-external`): + +- Handles public-facing traffic +- HTTPS (port 443) with TLS termination +- Dynamically creates listeners based on configured routes +- Integrates with cert-manager for automatic certificate provisioning +- Each hostname gets its own listener with dedicated TLS certificate + +**Internal Gateway** (`gw-internal`): + +- Handles cluster-internal traffic +- HTTP (port 80) without TLS +- Single listener accepting all namespaces + +### Route Configuration + +Routes are managed through the `envoy-configs` Helm chart, which generates HTTPRoute and TLSRoute resources based on declarative configuration. + +#### HTTP Routes + +HTTP routes terminate TLS at the Gateway and forward HTTP traffic to backend services: + +```yaml +routes: + http: + - name: keystone + fqdn: keystone.example.com + namespace: openstack + service: + name: keystone-api + port: 5000 +``` + +This generates: + +1. A listener on the external Gateway for `keystone.example.com:443` +2. An HTTPRoute in the `openstack` namespace +3. A cert-manager Certificate resource named `keystone-tls` + +#### TLS Routes (Passthrough) + +TLS routes pass encrypted traffic directly to the backend without termination: + +```yaml +routes: + tls: + - name: argo-workflows + fqdn: workflows.example.com + namespace: argo + service: + name: argo-server + port: 2746 +``` + +Used when the backend service handles TLS itself (like Argo Workflows with HTTPS). + +#### HTTPS Backends + +For backends that expect HTTPS but you want TLS termination at the Gateway: + +```yaml +routes: + http: + - name: argo-workflows + fqdn: workflows.example.com + namespace: argo + service: + name: argo-server + port: 2746 + backendType: tls # Tells Envoy to use HTTPS to backend +``` + +This uses Envoy Gateway's Backend CRD to establish TLS connections to the backend service. + +## Migration Guide + +### Prerequisites + +Ensure your UnderStack deployment is using a recent version that includes: + +- Envoy Gateway component (automatically deployed via ArgoCD) +- cert-manager with Gateway API support enabled +- Updated bootstrap script with Gateway API configuration + +### Migration Steps for Existing Deployments + +The migration requires changes in your deployment repository (`deploy//`). Here's the complete process: + +#### 1. Disable ingress-nginx Controller + +In your `apps.yaml`, add ingress-nginx to the skip list: + +```yaml +- component: ingress-nginx + skip: true +``` + +#### 2. Create GatewayClass Resource + +Create `manifests/envoy-gateway/gateway-class.yaml`: + +```yaml +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: eg +spec: + controllerName: gateway.envoyproxy.io/gatewayclass-controller +``` + +And `manifests/envoy-gateway/kustomization.yaml`: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gateway-class.yaml +``` + +#### 3. Configure Gateway and Routes + +Create `helm-configs/envoy-configs.yaml` with your Gateway and route definitions: + +```yaml +# yaml-language-server: $schema=https://rackerlabs.github.io/understack/schema/component-envoy-configs.schema.json +gateways: + external: + name: external-gateway + namespace: envoy-gateway + className: eg + serviceAnnotations: + # If using Cilium L2 announcements + lbipam.cilium.io/ips: "10.4.35.199" + lbipam.cilium.io/sharing-cross-namespace: "openstack" + lbipam.cilium.io/sharing-key: "provisioning-service" + internal: + name: internal-gateway + namespace: envoy-gateway + className: eg + serviceAnnotations: + lbipam.cilium.io/ips: "10.4.35.199" + lbipam.cilium.io/sharing-cross-namespace: "openstack" + lbipam.cilium.io/sharing-key: "provisioning-service" + +routes: + http: + # OpenStack services + - fqdn: keystone.example.com + service: + name: keystone-api + port: 5000 + - fqdn: nova.example.com + service: + name: nova-api + port: 8774 + - fqdn: neutron.example.com + service: + name: neutron-server + port: 9696 + # Add all your other services... + + # Services with HTTPS backends + - fqdn: nautobot.example.com + namespace: nautobot + service: + name: nautobot-default + port: 443 + backendType: tls + - fqdn: workflows.example.com + namespace: argo + service: + name: argo-server + port: 2746 + backendType: tls +``` + +Create empty `manifests/envoy-configs/kustomization.yaml`: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: [] +``` + +#### 4. Remove Old Ingress Resources + +Delete any standalone Ingress manifests: + +```bash +# Example +rm manifests/argo-workflows/ingress.yaml +``` + +Update kustomization files to remove ingress references: + +```yaml +# manifests/argo-workflows/kustomization.yaml +resources: + - https://github.com/rackerlabs/understack.git//components/argo-workflows/?ref=v0.0.43 + # Remove: - ingress.yaml +``` + +#### 5. Disable Ingress in Helm Charts + +For components that generate their own Ingress resources (like monitoring stack), disable them in helm-configs: + +```yaml +# helm-configs/monitoring.yaml +grafana: + ingress: + enabled: false + +prometheus: + ingress: + enabled: false + +alertmanager: + ingress: + enabled: false +``` + +#### 6. Update Cilium L2 Policies + +If using Cilium L2 announcements, update the service selector to match Envoy Gateway: + +```yaml +# manifests/cilium/c-l2policies.yaml +spec: + serviceSelector: + matchLabels: + app.kubernetes.io/name: envoy # Changed from: app.kubernetes.io/instance: ingress-nginx +``` + +#### 7. Update Load Balancer IP Sharing + +Update any services that share IPs with the ingress controller: + +```yaml +# manifests/ironic/services-ironic.yaml +metadata: + annotations: + lbipam.cilium.io/sharing-cross-namespace: envoy-gateway # Changed from: ingress-nginx +``` + +#### 8. Update cert-manager Configuration + +If not already done, ensure cert-manager has Gateway API support enabled in `helm-configs/cert-manager.yaml`: + +```yaml +config: + enableGatewayApi: true + apiVersion: "controller.config.cert-manager.io/v1alpha1" + kind: "ControllerConfiguration" +``` + +#### 9. Apply Changes + +Commit and push your changes. ArgoCD will automatically: + +1. Deploy Envoy Gateway controller +2. Create the GatewayClass +3. Create Gateway resources with listeners +4. Create HTTPRoute/TLSRoute resources +5. Provision TLS certificates via cert-manager +6. Remove the old ingress-nginx controller + +### Adding New Applications + +When adding a new application that needs external access: + +1. **Add route configuration** to your site's `helm-configs/envoy-configs.yaml`: + + ```yaml + routes: + http: + - name: myapp + fqdn: myapp.example.com + namespace: myapp-namespace + service: + name: myapp-service + port: 8080 + ``` + +2. **For HTTPS backends**, add `backendType: tls`: + + ```yaml + routes: + http: + - name: myapp + fqdn: myapp.example.com + namespace: myapp-namespace + service: + name: myapp-service + port: 8443 + backendType: tls + ``` + +3. **For TLS passthrough** (no termination at Gateway): + + ```yaml + routes: + tls: + - name: myapp + fqdn: myapp.example.com + namespace: myapp-namespace + service: + name: myapp-service + port: 8443 + ``` + +4. **Do not create Ingress resources** - all routing is managed centrally through `envoy-configs.yaml` + +5. **For OpenStack Helm charts**, ensure these settings are configured: + + ```yaml + network: + use_external_ingress_controller: true + + manifests: + ingress_api: false + service_ingress_api: false + + endpoints: + identity: + scheme: + public: https + port: + api: + public: 443 + ``` + +### Troubleshooting + +**Check Gateway status**: + +```bash +kubectl get gateway -n envoy-gateway +kubectl describe gateway gw-external -n envoy-gateway +``` + +**Check Route status**: + +```bash +kubectl get httproute -A +kubectl describe httproute -n +``` + +**View Envoy Gateway logs**: + +```bash +kubectl logs -n envoy-gateway -l control-plane=envoy-gateway +``` + +**Check generated Envoy configuration**: + +```bash +# Find the Envoy proxy pod +kubectl get pods -n envoy-gateway -l gateway.envoyproxy.io/owning-gateway-name=gw-external + +# View configuration +kubectl exec -n envoy-gateway -- curl localhost:19000/config_dump +``` + +**Common issues**: + +- **Route not working**: Check that the HTTPRoute's `parentRefs` correctly references the Gateway name and namespace +- **Certificate issues**: Verify the Gateway annotation `cert-manager.io/cluster-issuer` is set and the ClusterIssuer exists +- **Backend connection failures**: For HTTPS backends, ensure `backendType: tls` is set and the Backend resource is created +- **No traffic reaching HTTPRoutes**: Check if the Envoy Gateway Service has an external IP assigned: + + ```bash + kubectl get svc -n envoy-gateway + ``` + + If the Service is stuck without an external IP, the old ingress-nginx Service may still exist and be holding the port. The `skip: true` setting only prevents new resources from being created but does not prune existing ones. Manually remove the old ingress-nginx resources: + + ```bash + # Check for old ingress-nginx resources + kubectl get svc -n ingress-nginx + kubectl get deploy -n ingress-nginx + + # Remove the old controller + kubectl delete namespace ingress-nginx + ``` + +## Configuration Reference + +### envoy-configs Helm Chart + +The `envoy-configs` chart is deployed via ArgoCD and generates Gateway and Route resources. + +**Location**: `components/envoy-configs/` + +**Deployment**: `apps/site/envoy-configs.yaml` + +**Site-specific values**: `deploy//helm-configs/envoy-configs.yaml` + +### Route Schema + +```yaml +routes: + http: + - name: string # Route name (optional, defaults to first part of fqdn) + fqdn: string # Fully qualified domain name + namespace: string # Namespace for the HTTPRoute resource + path: string # Path prefix (default: "/") + pathType: string # PathPrefix or Exact (default: "PathPrefix") + service: + name: string # Backend service name + port: integer # Backend service port + backendType: string # Optional: "tls" for HTTPS backends + filters: [] # Optional: Gateway API filters + from: string # Optional: "All" or "Selector" for namespace selection + selector: {} # Optional: Label selector for allowed namespaces + + tls: + - name: string # Route name (optional) + fqdn: string # Fully qualified domain name + namespace: string # Namespace for the TLSRoute resource + service: + name: string # Backend service name + port: integer # Backend service port +``` + +## Additional Resources + +- [Kubernetes Gateway API Documentation](https://gateway-api.sigs.k8s.io/) +- [Envoy Gateway Documentation](https://gateway.envoyproxy.io/) +- [Gateway API Migration Guide](https://gateway-api.sigs.k8s.io/guides/migrating-from-ingress/) +- [cert-manager Gateway API Support](https://cert-manager.io/docs/usage/gateway/) diff --git a/docs/operator-guide/index.md b/docs/operator-guide/index.md index 0d1233ba8..9833b948e 100644 --- a/docs/operator-guide/index.md +++ b/docs/operator-guide/index.md @@ -33,4 +33,10 @@ clouds: In the above case `uc-prod-infra` would be the operator area while `uc-prod` would be the regular project area. +## Infrastructure Topics + +- [Gateway API Migration Guide](gateway-api.md) - Migration from ingress-nginx to Kubernetes Gateway API with Envoy Gateway +- [Argo Workflows](workflows.md) - Workflow orchestration and troubleshooting +- [Monitoring Stack](monitoring.md) - Prometheus and Grafana monitoring + [cli]: <../user-guide/openstack-cli.md> diff --git a/docs/schema/component-envoy-configs.schema.json b/docs/schema/component-envoy-configs.schema.json new file mode 120000 index 000000000..1d7fecaba --- /dev/null +++ b/docs/schema/component-envoy-configs.schema.json @@ -0,0 +1 @@ +../../components/envoy-configs/values.schema.json \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 90efe9b9c..4c3b278a5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -165,6 +165,7 @@ nav: - 'Infrastructure': - operator-guide/workflows.md - operator-guide/monitoring.md + - operator-guide/gateway-api.md - operator-guide/bmc-password.md - operator-guide/mariadb-operator.md - operator-guide/mariadb-upgrade-runbook.md