Skip to content

Commit 24274f9

Browse files
authored
Merge pull request #21860 from wireapp/envoy-gateway
build: envoy gateway support (helm) [WPB-24493]
2 parents dc7a703 + af62d54 commit 24274f9

9 files changed

Lines changed: 278 additions & 10 deletions

File tree

charts/webapp/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
apiVersion: v1
22
description: A Helm chart for the Wire webapp in Kubernetes
33
name: webapp
4-
version: 0.5.0
4+
version: 0.6.0

charts/webapp/templates/_helpers.tpl

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,103 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
4141
{{- end -}}
4242

4343
{{- define "webapp.validateDomainConfig" -}}
44-
{{- if or .Values.ingress.enabled .Values.tls.enabled }}
44+
{{- $routingMode := default "nginx" .Values.routing.mode | lower -}}
45+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
46+
{{- if or $routingEnabled .Values.tls.enabled }}
4547
{{- if not .Values.webappDomain }}
46-
{{- fail "webappDomain must be set when enabling ingress or tls" }}
48+
{{- fail "webappDomain must be set when enabling routing or tls" }}
4749
{{- end }}
4850
{{- end }}
49-
{{- if and .Values.tls.enabled (not .Values.ingress.enabled) }}
50-
{{- fail "ingress.enabled must be true when tls.enabled is true" }}
51+
{{- if and (ne $routingMode "nginx") (ne $routingMode "envoy") (ne $routingMode "migration") }}
52+
{{- fail "routing.mode must be one of nginx, envoy, or migration" }}
53+
{{- end }}
54+
{{- if and (or (eq $routingMode "envoy") (eq $routingMode "migration")) (not $routingEnabled) }}
55+
{{- fail "routing.enabled must be true when routing.mode is envoy or migration" }}
56+
{{- end }}
57+
{{- if and $routingEnabled (or (eq $routingMode "envoy") (eq $routingMode "migration")) (empty .Values.gateway.name) }}
58+
{{- fail "gateway.name must be set when routing.mode is envoy or migration" }}
59+
{{- end }}
60+
{{- if and $routingEnabled (eq $routingMode "migration") (and (ne (default "nginx" .Values.routing.migration.primary | lower) "nginx") (ne (default "nginx" .Values.routing.migration.primary | lower) "envoy")) }}
61+
{{- fail "routing.migration.primary must be one of nginx or envoy" }}
62+
{{- end }}
63+
{{- if and .Values.ingress.renderCSPInIngress (eq $routingMode "envoy") }}
64+
{{- fail "ingress.renderCSPInIngress only works with routing.mode=nginx or migration" }}
65+
{{- end }}
66+
{{- if and .Values.tls.enabled (not $routingEnabled) }}
67+
{{- fail "routing.enabled must be true when tls.enabled is true" }}
5168
{{- end }}
5269
{{- if and .Values.tls.enabled (not .Values.tls.useCertManager) (empty .Values.tls.existingSecretName) }}
5370
{{- fail "When tls.enabled is true, either tls.useCertManager must be true or tls.existingSecretName must be set" }}
5471
{{- end }}
5572
{{- end -}}
5673

74+
{{- define "webapp.routingEnabled" -}}
75+
{{- or .Values.routing.enabled .Values.ingress.enabled -}}
76+
{{- end -}}
77+
78+
{{- define "webapp.routingMode" -}}
79+
{{- default "nginx" .Values.routing.mode | lower -}}
80+
{{- end -}}
81+
82+
{{- define "webapp.routingPrimaryController" -}}
83+
{{- $mode := include "webapp.routingMode" . -}}
84+
{{- if eq $mode "migration" -}}
85+
{{- default "nginx" .Values.routing.migration.primary | lower -}}
86+
{{- else -}}
87+
{{- $mode -}}
88+
{{- end -}}
89+
{{- end -}}
90+
91+
{{- define "webapp.externalDnsWeight" -}}
92+
{{- $ctx := .ctx -}}
93+
{{- $kind := .kind -}}
94+
{{- if eq (include "webapp.routingMode" $ctx) "migration" -}}
95+
{{- if eq (include "webapp.routingPrimaryController" $ctx) $kind -}}
96+
100
97+
{{- else -}}
98+
0
99+
{{- end -}}
100+
{{- end -}}
101+
{{- end -}}
102+
103+
{{- define "webapp.externalDnsSetIdentifier" -}}
104+
{{- $ctx := .ctx -}}
105+
{{- $kind := .kind -}}
106+
{{- if eq (include "webapp.routingMode" $ctx) "migration" -}}
107+
{{- printf "%s-%s" (include "webapp.baseName" $ctx) $kind -}}
108+
{{- end -}}
109+
{{- end -}}
110+
111+
{{- define "webapp.listenerSetName" -}}
112+
{{- printf "%s-listeners" (include "webapp.baseName" .) | trunc 63 | trimSuffix "-" -}}
113+
{{- end -}}
114+
115+
{{- define "webapp.listenerName" -}}
116+
{{- if .Values.gateway.sectionName -}}
117+
{{- .Values.gateway.sectionName -}}
118+
{{- else if .Values.tls.enabled -}}
119+
https
120+
{{- else -}}
121+
http
122+
{{- end -}}
123+
{{- end -}}
124+
125+
{{- define "webapp.listenerProtocol" -}}
126+
{{- if .Values.tls.enabled -}}
127+
HTTPS
128+
{{- else -}}
129+
HTTP
130+
{{- end -}}
131+
{{- end -}}
132+
133+
{{- define "webapp.listenerPort" -}}
134+
{{- if .Values.tls.enabled -}}
135+
443
136+
{{- else -}}
137+
80
138+
{{- end -}}
139+
{{- end -}}
140+
57141
{{- define "webapp.certificateSecretName" -}}
58142
{{- printf "%s-managed-tls-certificate" (include "webapp.fullname" .) -}}
59143
{{- end -}}

charts/webapp/templates/certificate.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
{{- if and .Values.tls.enabled .Values.tls.useCertManager .Values.ingress.enabled (empty .Values.tls.existingSecretName) }}
1+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
2+
{{- if and .Values.tls.enabled .Values.tls.useCertManager $routingEnabled (empty .Values.tls.existingSecretName) }}
23
{{- include "webapp.validateDomainConfig" . }}
34
apiVersion: cert-manager.io/v1
45
kind: Certificate
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{{- $routingMode := include "webapp.routingMode" . -}}
2+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
3+
{{- if and $routingEnabled (or (eq $routingMode "envoy") (eq $routingMode "migration")) }}
4+
{{- include "webapp.validateDomainConfig" . }}
5+
apiVersion: gateway.networking.k8s.io/v1
6+
kind: HTTPRoute
7+
metadata:
8+
name: {{ include "webapp.baseName" . }}
9+
labels:
10+
app: {{ include "webapp.baseName" . }}
11+
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
12+
release: {{ .Release.Name }}
13+
heritage: {{ .Release.Service }}
14+
{{- $setIdentifier := include "webapp.externalDnsSetIdentifier" (dict "ctx" . "kind" "envoy") | trim -}}
15+
{{- $weight := include "webapp.externalDnsWeight" (dict "ctx" . "kind" "envoy") | trim -}}
16+
{{- if or .Values.gateway.httpRouteAnnotations $setIdentifier $weight }}
17+
annotations:
18+
{{- range $key, $val := .Values.gateway.httpRouteAnnotations }}
19+
{{ $key }}: {{ $val | quote }}
20+
{{- end }}
21+
{{- if $setIdentifier }}
22+
external-dns.alpha.kubernetes.io/set-identifier: {{ $setIdentifier | quote }}
23+
{{- end }}
24+
{{- if $weight }}
25+
external-dns.alpha.kubernetes.io/aws-weight: {{ $weight | quote }}
26+
{{- end }}
27+
{{- end }}
28+
spec:
29+
parentRefs:
30+
- name: {{ include "webapp.listenerSetName" . | quote }}
31+
kind: ListenerSet
32+
group: gateway.networking.k8s.io
33+
sectionName: {{ include "webapp.listenerName" . | quote }}
34+
hostnames:
35+
- {{ .Values.webappDomain | quote }}
36+
rules:
37+
- matches:
38+
- path:
39+
type: PathPrefix
40+
value: /
41+
backendRefs:
42+
- name: {{ include "webapp.httpServiceName" . }}
43+
port: {{ .Values.service.http.port | default .Values.service.http.internalPort }}
44+
kind: Service
45+
{{- end }}

charts/webapp/templates/ingress.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
{{- if .Values.ingress.enabled }}
1+
{{- $routingMode := include "webapp.routingMode" . -}}
2+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
3+
{{- if and $routingEnabled (or (eq $routingMode "nginx") (eq $routingMode "migration")) }}
24
{{- include "webapp.validateDomainConfig" . }}
35
{{- $ingressClass := default "nginx" .Values.ingress.className -}}
46
{{- $backendDomain := "" -}}
@@ -17,10 +19,15 @@ metadata:
1719
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
1820
release: {{ .Release.Name }}
1921
heritage: {{ .Release.Service }}
22+
{{- if or .Values.ingress.annotations .Values.ingress.renderCSPInIngress (eq $routingMode "migration") }}
2023
annotations:
2124
{{- range $key, $val := .Values.ingress.annotations }}
2225
{{ $key }}: {{ $val | quote }}
2326
{{- end }}
27+
{{- $setIdentifier := include "webapp.externalDnsSetIdentifier" (dict "ctx" . "kind" "nginx") | trim -}}
28+
{{- if $setIdentifier }}
29+
external-dns.alpha.kubernetes.io/set-identifier: {{ $setIdentifier | quote }}
30+
{{- end }}
2431
{{- if .Values.ingress.renderCSPInIngress }}
2532
{{- if not (contains $ingressClass "nginx") }}
2633
{{- fail "In ingress CSP header setting only works with a 'nginx' controller. (Rename it to 'nginx-*' if it is one.)" }}
@@ -50,6 +57,11 @@ metadata:
5057
more_set_headers "content-security-policy: $CSP";
5158
}
5259
{{- end }}
60+
{{- $weight := include "webapp.externalDnsWeight" (dict "ctx" . "kind" "nginx") | trim -}}
61+
{{- if $weight }}
62+
external-dns.alpha.kubernetes.io/aws-weight: {{ $weight | quote }}
63+
{{- end }}
64+
{{- end }}
5365
spec:
5466
ingressClassName: {{ $ingressClass | quote }}
5567
{{- if .Values.tls.enabled }}

charts/webapp/templates/issuer.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
{{- if and .Values.tls.enabled .Values.tls.useCertManager .Values.tls.createIssuer .Values.ingress.enabled (empty .Values.tls.existingSecretName) }}
1+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
2+
{{- if and .Values.tls.enabled .Values.tls.useCertManager .Values.tls.createIssuer $routingEnabled (empty .Values.tls.existingSecretName) }}
23
{{- include "webapp.validateDomainConfig" . }}
4+
{{- $solverController := include "webapp.routingPrimaryController" . -}}
35
apiVersion: cert-manager.io/v1
46
{{- if or (eq .Values.tls.issuer.kind "Issuer") (eq .Values.tls.issuer.kind "ClusterIssuer") }}
57
kind: "{{ .Values.tls.issuer.kind }}"
@@ -24,9 +26,18 @@ spec:
2426
solvers:
2527
{{- if .Values.certManager.customSolvers }}
2628
{{ toYaml .Values.certManager.customSolvers | indent 6 }}
29+
{{- else }}
30+
{{- if eq $solverController "envoy" }}
31+
- http01:
32+
gatewayHTTPRoute:
33+
parentRefs:
34+
- name: {{ required "gateway.name must be set when routing.mode is envoy or migration" .Values.gateway.name | quote }}
35+
namespace: {{ default .Release.Namespace .Values.gateway.namespace | quote }}
36+
kind: Gateway
2737
{{- else }}
2838
- http01:
2939
ingress:
3040
class: {{ default "nginx" .Values.ingress.className }}
3141
{{- end }}
42+
{{- end }}
3243
{{- end -}}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{{- $routingMode := include "webapp.routingMode" . -}}
2+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
3+
{{- if and $routingEnabled (or (eq $routingMode "envoy") (eq $routingMode "migration")) }}
4+
{{- include "webapp.validateDomainConfig" . }}
5+
apiVersion: gateway.networking.k8s.io/v1
6+
kind: ListenerSet
7+
metadata:
8+
name: {{ include "webapp.listenerSetName" . }}
9+
labels:
10+
app: {{ include "webapp.baseName" . }}
11+
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
12+
release: {{ .Release.Name }}
13+
heritage: {{ .Release.Service }}
14+
spec:
15+
parentRef:
16+
name: {{ required "gateway.name must be set when routing.mode is envoy or migration" .Values.gateway.name | quote }}
17+
{{- if .Values.gateway.namespace }}
18+
namespace: {{ .Values.gateway.namespace | quote }}
19+
{{- else }}
20+
namespace: {{ .Release.Namespace | quote }}
21+
{{- end }}
22+
kind: Gateway
23+
group: gateway.networking.k8s.io
24+
listeners:
25+
- name: {{ include "webapp.listenerName" . | quote }}
26+
hostname: {{ .Values.webappDomain | quote }}
27+
protocol: {{ include "webapp.listenerProtocol" . | quote }}
28+
port: {{ include "webapp.listenerPort" . }}
29+
{{- if .Values.tls.enabled }}
30+
tls:
31+
mode: Terminate
32+
certificateRefs:
33+
- kind: Secret
34+
name: {{ include "webapp.tlsSecretName" . | quote }}
35+
{{- end }}
36+
{{- end }}

charts/webapp/templates/service.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
{{- if .Values.ingress.enabled }}
1+
{{- $routingEnabled := eq (include "webapp.routingEnabled" . | trim) "true" -}}
2+
{{- if $routingEnabled }}
23
{{- $appName := include "webapp.baseName" . -}}
34
apiVersion: v1
45
kind: Service

charts/webapp/values.yaml

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,92 @@ appendReleaseNameToResources: false
1818

1919
# webappDomain: webapp.example.com
2020

21-
ingress:
21+
routing:
22+
# `routing.enabled` controls whether the chart renders the shared HTTP Service
23+
# plus either an Ingress (nginx mode) or Gateway API resources (envoy or
24+
# migration mode). `ingress.enabled` remains a deprecated alias for one
25+
# release so older values files keep working during the rename.
2226
enabled: false
27+
# Controller mode for web traffic:
28+
# - nginx: render only a Kubernetes Ingress
29+
# - envoy: render only a Gateway API HTTPRoute
30+
# - migration: render both and split external-dns weights between them
31+
mode: nginx
32+
migration:
33+
# Which controller should receive external-dns weight 100 during migration.
34+
# The other resource receives weight 0.
35+
primary: nginx
36+
37+
ingress:
38+
# nginx Ingress settings.
2339
className: nginx
2440
annotations: {}
41+
# nginx-only override for proxy-side CSP injection. The webapp server already
42+
# emits CSP headers itself, so Envoy mode does not need a proxy-side CSP path.
2543
renderCSPInIngress: false
2644

45+
gateway:
46+
# Envoy Gateway / Gateway API expectations when routing.mode is envoy or migration:
47+
# - ListenerSet is a Gateway API standard-channel resource as of Gateway API v1.5.0.
48+
# - Use an Envoy Gateway release that supports ListenerSet in your cluster; recent
49+
# Envoy Gateway 1.8.x release notes and tests use the stable `ListenerSet` API.
50+
# - If you are running an older Envoy Gateway release, check that release's docs for
51+
# any feature gate or compatibility notes before enabling this chart.
52+
# - A Gateway (gateway.networking.k8s.io/v1) must already exist, or be created separately.
53+
# - In the shared setup we use in staging, the Gateway lives in a dedicated
54+
# namespace such as `web-gateway` and the chart's ListenerSet points there
55+
# via `gateway.namespace`.
56+
# - spec.gatewayClassName must point at the Envoy Gateway GatewayClass.
57+
# - spec.allowedListeners must allow ListenerSet attachments from this chart's namespace.
58+
# `namespaces.from: All` is the broadest choice if you want to permit any namespace.
59+
# - ExternalDNS must run with `--gateway-listener-sets` so it follows the ListenerSet
60+
# parentRef and publishes DNS targets for envoy or migration mode. Without it,
61+
# Envoy may accept the route while ExternalDNS emits no target, which breaks the
62+
# weighted migration path. That flag is disabled by default and requires Gateway
63+
# API v1.5+ CRDs.
64+
# Example:
65+
# apiVersion: gateway.networking.k8s.io/v1
66+
# kind: Gateway
67+
# metadata:
68+
# name: webapp-gateway
69+
# namespace: web-gateway
70+
# spec:
71+
# gatewayClassName: envoy # use the GatewayClass installed by Envoy Gateway
72+
# allowedListeners:
73+
# namespaces:
74+
# from: All
75+
# listeners:
76+
# - name: http
77+
# protocol: HTTP
78+
# port: 80
79+
# allowedRoutes:
80+
# namespaces:
81+
# from: All
82+
# - This chart creates a ListenerSet in the release namespace and an HTTPRoute that
83+
# attaches to it. When using a shared Gateway namespace, set `gateway.namespace`
84+
# to that namespace.
85+
# - If tls.useCertManager=true and you rely on the default HTTP01 solver, cert-manager's
86+
# Gateway API integration must be enabled. When `gateway.namespace` differs from the
87+
# release namespace, the port 80 listener must also allow routes from the Certificate
88+
# namespace, for example with `allowedRoutes.namespaces.from: All`.
89+
# Gateway name used when routing.mode is envoy or migration.
90+
name: ""
91+
# Optional namespace of the Gateway. Defaults to the release namespace.
92+
# Set this to a shared Gateway namespace like `web-gateway` when you keep the
93+
# Envoy Gateway entrypoint separate from the application namespace.
94+
namespace: ""
95+
# Listener section name used by the ListenerSet and HTTPRoute parentRef.
96+
# Defaults to https when tls.enabled=true, otherwise http.
97+
sectionName: ""
98+
# HTTPRoute-specific annotations.
99+
httpRouteAnnotations: {}
100+
27101
tls:
28102
enabled: false
103+
# Set this to true when cert-manager should provision the certificate using
104+
# its Gateway API HTTP-01 solver. This requires cert-manager's Gateway API
105+
# integration to be enabled, and the Gateway listener must allow the solver
106+
# namespace when the Gateway lives outside the release namespace.
29107
useCertManager: false
30108
createIssuer: false
31109
# existingSecretName: "" # set this if you created e.g. a wildcard cert outside this chart

0 commit comments

Comments
 (0)