feat: add Gateway API support (#1073)

Add full Gateway API support for exposing Gitea via HTTPRoute, TCPRoute, BackendTLSPolicy, and ClientSettingsPolicy resources.

New templates:
- `httpRoute.yaml` — renders an HTTPRoute with configurable
  parentRefs, hostnames, and rules (defaults to PathPrefix `/`)
- `tcpRoute.yaml` — renders a TCPRoute for SSH traffic
- `backendTLSPolicy.yaml` — renders a BackendTLSPolicy for
  encrypted backend connections with required validation config
- `clientSettingsPolicy.yaml` — renders an NGINX Gateway Fabric
  ClientSettingsPolicy to raise the request body size limit

Infrastructure:
- `gatewayAPI.enabled` global toggle gates all resources
- Resources grouped under `gatewayAPI.core.*` and `gatewayAPI.nginx.*`
- Helper templates extracted into dedicated `_*.tpl` files
- Service name helpers (`gitea.service.http.name`, `gitea.service.ssh.name`)
  extracted into `_services.tpl`; service templates renamed to camelCase
- `ROOT_URL`, `DOMAIN`, and `SSH_DOMAIN` auto-resolve from
  `httpRoute.hostnames[0]`; `httpRoute.tls` switches to `https`

Documentation:
- New `docs/gateway-api.md` with topology examples, BackendTLSPolicy
  setup, sectionName guidance, SSH considerations, and NGINX body
  size limit configuration
- `.github/copilot-instructions.md` with project conventions
- README parameter table auto-generated via `make readme`

Tests:
- Helm unit tests for all four new resource templates
- Config tests for hostname/TLS resolution from Gateway API values

Co-authored-by: Todd Marimon <toddmarimon@gmail.com>
This commit is contained in:
Todd Marimon
2026-07-19 16:25:28 +00:00
committed by Markus Pesch
parent 5005037dbf
commit 7747a001f7
25 changed files with 1200 additions and 40 deletions
+4
View File
@@ -247,6 +247,8 @@ app.kubernetes.io/instance: {{ .Release.Name }}
{{- define "gitea.public_hostname" -}}
{{- if and .Values.route.enabled .Values.route.host -}}
{{ tpl .Values.route.host . }}
{{- else if and .Values.gatewayAPI.enabled .Values.gatewayAPI.core.httpRoute.enabled (gt (len .Values.gatewayAPI.core.httpRoute.hostnames) 0) -}}
{{ tpl (index .Values.gatewayAPI.core.httpRoute.hostnames 0) $ }}
{{- else if gt (len .Values.ingress.hosts) 0 -}}
{{ tpl (index .Values.ingress.hosts 0).host $ }}
{{- else -}}
@@ -308,6 +310,8 @@ app.kubernetes.io/instance: {{ .Release.Name }}
https
{{- else if and .Values.ingress.enabled (gt (len .Values.ingress.tls) 0) -}}
https
{{- else if and .Values.gatewayAPI.enabled .Values.gatewayAPI.core.httpRoute.enabled .Values.gatewayAPI.core.httpRoute.tls -}}
https
{{- else -}}
{{ .Values.gitea.config.server.PROTOCOL }}
{{- end -}}
+30
View File
@@ -0,0 +1,30 @@
{{/* vim: set filetype=mustache: */}}
{{/* annotations */}}
{{- define "gitea.backendTLSPolicy.annotations" -}}
{{- with .Values.gatewayAPI.core.backendTLSPolicy.annotations }}
{{- toYaml . -}}
{{- end }}
{{- end }}
{{/* enabled */}}
{{- define "gitea.backendTLSPolicy.enabled" -}}
{{- if and .Values.gatewayAPI.enabled
.Values.gatewayAPI.core.backendTLSPolicy.enabled
-}}
true
{{- else -}}
false
{{- end -}}
{{- end }}
{{/* labels */}}
{{- define "gitea.backendTLSPolicy.labels" -}}
{{ include "gitea.labels" . }}
{{- with .Values.gatewayAPI.core.backendTLSPolicy.labels }}
{{ toYaml . }}
{{- end }}
{{- end }}
@@ -0,0 +1,30 @@
{{/* vim: set filetype=mustache: */}}
{{/* annotations */}}
{{- define "gitea.clientSettingsPolicies.annotations" -}}
{{- with .Values.gatewayAPI.nginx.clientSettingsPolicies.annotations }}
{{- toYaml . -}}
{{- end }}
{{- end }}
{{/* enabled */}}
{{- define "gitea.clientSettingsPolicies.enabled" -}}
{{- if and .Values.gatewayAPI.enabled
.Values.gatewayAPI.nginx.clientSettingsPolicies.enabled
-}}
true
{{- else -}}
false
{{- end -}}
{{- end }}
{{/* labels */}}
{{- define "gitea.clientSettingsPolicies.labels" -}}
{{ include "gitea.labels" . }}
{{- with .Values.gatewayAPI.nginx.clientSettingsPolicies.labels }}
{{ toYaml . }}
{{- end }}
{{- end }}
+30
View File
@@ -0,0 +1,30 @@
{{/* vim: set filetype=mustache: */}}
{{/* annotations */}}
{{- define "gitea.httpRoute.annotations" -}}
{{- with .Values.gatewayAPI.core.httpRoute.annotations }}
{{- toYaml . -}}
{{- end }}
{{- end }}
{{/* enabled */}}
{{- define "gitea.httpRoute.enabled" -}}
{{- if and .Values.gatewayAPI.enabled
.Values.gatewayAPI.core.httpRoute.enabled
-}}
true
{{- else -}}
false
{{- end -}}
{{- end }}
{{/* labels */}}
{{- define "gitea.httpRoute.labels" -}}
{{ include "gitea.labels" . }}
{{- with .Values.gatewayAPI.core.httpRoute.labels }}
{{ toYaml . }}
{{- end }}
{{- end }}
+11
View File
@@ -0,0 +1,11 @@
{{/* vim: set filetype=mustache: */}}
{{/* names */}}
{{- define "gitea.service.http.name" -}}
{{ include "gitea.fullname" . }}-http
{{- end }}
{{- define "gitea.service.ssh.name" -}}
{{ include "gitea.fullname" . }}-ssh
{{- end }}
+30
View File
@@ -0,0 +1,30 @@
{{/* vim: set filetype=mustache: */}}
{{/* annotations */}}
{{- define "gitea.tcpRoute.annotations" -}}
{{- with .Values.gatewayAPI.core.tcpRoute.annotations }}
{{- toYaml . -}}
{{- end }}
{{- end }}
{{/* enabled */}}
{{- define "gitea.tcpRoute.enabled" -}}
{{- if and .Values.gatewayAPI.enabled
.Values.gatewayAPI.core.tcpRoute.enabled
-}}
true
{{- else -}}
false
{{- end -}}
{{- end }}
{{/* labels */}}
{{- define "gitea.tcpRoute.labels" -}}
{{ include "gitea.labels" . }}
{{- with .Values.gatewayAPI.core.tcpRoute.labels }}
{{ toYaml . }}
{{- end }}
{{- end }}
+30
View File
@@ -0,0 +1,30 @@
{{- if eq (include "gitea.backendTLSPolicy.enabled" .) "true" -}}
{{- if not (keys .Values.gatewayAPI.core.backendTLSPolicy.validation) }}
{{- fail "gatewayAPI.core.backendTLSPolicy.validation is required" }}
{{- end }}
---
apiVersion: gateway.networking.k8s.io/v1
kind: BackendTLSPolicy
metadata:
{{- with (include "gitea.backendTLSPolicy.annotations" .) }}
annotations:
{{- . | nindent 4 }}
{{- end }}
{{- with (include "gitea.backendTLSPolicy.labels" .) }}
labels:
{{- . | nindent 4 }}
{{- end }}
name: {{ include "gitea.fullname" . }}
namespace: {{ .Values.namespace | default .Release.Namespace }}
spec:
targetRefs:
{{- if .Values.gatewayAPI.core.backendTLSPolicy.targetRefs }}
{{- toYaml .Values.gatewayAPI.core.backendTLSPolicy.targetRefs | nindent 4 }}
{{- else }}
- group: ""
kind: Service
name: {{ include "gitea.service.http.name" . }}
{{- end }}
validation:
{{- toYaml .Values.gatewayAPI.core.backendTLSPolicy.validation | nindent 4 }}
{{- end }}
+30
View File
@@ -0,0 +1,30 @@
{{- if eq (include "gitea.clientSettingsPolicies.enabled" .) "true" -}}
{{- if not (keys .Values.gatewayAPI.nginx.clientSettingsPolicies.body) }}
{{- fail "gatewayAPI.nginx.clientSettingsPolicies.body is required" }}
{{- end }}
---
apiVersion: gateway.nginx.org/v1alpha1
kind: ClientSettingsPolicy
metadata:
{{- with (include "gitea.clientSettingsPolicies.annotations" .) }}
annotations:
{{- . | nindent 4 }}
{{- end }}
{{- with (include "gitea.clientSettingsPolicies.labels" .) }}
labels:
{{- . | nindent 4 }}
{{- end }}
name: {{ include "gitea.fullname" . }}
namespace: {{ .Values.namespace | default .Release.Namespace }}
spec:
targetRef:
{{- if .Values.gatewayAPI.nginx.clientSettingsPolicies.targetRef }}
{{- toYaml .Values.gatewayAPI.nginx.clientSettingsPolicies.targetRef | nindent 4 }}
{{- else }}
group: gateway.networking.k8s.io
kind: HTTPRoute
name: {{ include "gitea.fullname" . }}
{{- end }}
body:
{{- toYaml .Values.gatewayAPI.nginx.clientSettingsPolicies.body | nindent 4 }}
{{- end }}
+42
View File
@@ -0,0 +1,42 @@
{{- if eq (include "gitea.httpRoute.enabled" .) "true" -}}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
{{- with (include "gitea.httpRoute.annotations" .) }}
annotations:
{{- . | nindent 4 }}
{{- end }}
{{- with (include "gitea.httpRoute.labels" .) }}
labels:
{{- . | nindent 4 }}
{{- end }}
name: {{ include "gitea.fullname" . }}
namespace: {{ .Values.namespace | default .Release.Namespace }}
spec:
parentRefs:
{{- if .Values.gatewayAPI.core.httpRoute.parentRefs }}
{{- toYaml .Values.gatewayAPI.core.httpRoute.parentRefs | nindent 4 }}
{{- else }}
{{- fail "gatewayAPI.core.httpRoute.parentRefs is required" }}
{{- end }}
{{- with .Values.gatewayAPI.core.httpRoute.hostnames }}
hostnames:
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end }}
rules:
{{- if .Values.gatewayAPI.core.httpRoute.rules }}
{{- tpl (toYaml .Values.gatewayAPI.core.httpRoute.rules) $ | nindent 4 }}
{{- else }}
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- group: ""
kind: Service
name: {{ include "gitea.service.http.name" . }}
port: {{ .Values.service.http.port }}
weight: 1
{{- end }}
{{- end }}
@@ -1,15 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "gitea.fullname" . }}-http
namespace: {{ .Values.namespace | default .Release.Namespace }}
annotations:
{{- toYaml .Values.service.http.annotations | nindent 4 }}
labels:
{{- include "gitea.labels" . | nindent 4 }}
{{- if .Values.service.http.labels }}
{{- toYaml .Values.service.http.labels | nindent 4 }}
{{- end }}
annotations:
{{- toYaml .Values.service.http.annotations | nindent 4 }}
name: {{ include "gitea.service.http.name" . }}
namespace: {{ .Values.namespace | default .Release.Namespace }}
spec:
type: {{ .Values.service.http.type }}
{{- if eq .Values.service.http.type "LoadBalancer" }}
+3 -3
View File
@@ -36,7 +36,7 @@ spec:
pathType: {{ default "Prefix" $.Values.ingress.pathType }}
backend:
service:
name: {{ $fullName }}-http
name: {{ include "gitea.service.http.name" $ }}
port:
number: {{ $httpPort }}
{{- else }}
@@ -44,7 +44,7 @@ spec:
pathType: {{ .pathType | default "Prefix" }}
backend:
service:
name: {{ $fullName }}-http
name: {{ include "gitea.service.http.name" $ }}
port:
number: {{ $httpPort }}
{{- end }}
@@ -54,7 +54,7 @@ spec:
pathType: "Prefix"
backend:
service:
name: {{ $fullName }}-http
name: {{ include "gitea.service.http.name" $ }}
port:
number: {{ $httpPort }}
{{- end }}
+1 -1
View File
@@ -20,7 +20,7 @@ spec:
{{- end }}
to:
kind: Service
name: {{ $fullName }}-http
name: {{ include "gitea.service.http.name" . }}
port:
targetPort: http
wildcardPolicy: {{ .Values.route.wildcardPolicy }}
@@ -1,15 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "gitea.fullname" . }}-ssh
namespace: {{ .Values.namespace | default .Release.Namespace }}
annotations:
{{- toYaml .Values.service.ssh.annotations | nindent 4 }}
labels:
{{- include "gitea.labels" . | nindent 4 }}
{{- if .Values.service.ssh.labels }}
{{- toYaml .Values.service.ssh.labels | nindent 4 }}
{{- end }}
annotations:
{{- toYaml .Values.service.ssh.annotations | nindent 4 }}
name: {{ include "gitea.service.ssh.name" . }}
namespace: {{ .Values.namespace | default .Release.Namespace }}
spec:
type: {{ .Values.service.ssh.type }}
{{- if eq .Values.service.ssh.type "LoadBalancer" }}
+34
View File
@@ -0,0 +1,34 @@
{{- if eq (include "gitea.tcpRoute.enabled" .) "true" -}}
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
{{- with (include "gitea.tcpRoute.annotations" .) }}
annotations:
{{- . | nindent 4 }}
{{- end }}
{{- with (include "gitea.tcpRoute.labels" .) }}
labels:
{{- . | nindent 4 }}
{{- end }}
name: {{ include "gitea.fullname" . }}
namespace: {{ .Values.namespace | default .Release.Namespace }}
spec:
parentRefs:
{{- if .Values.gatewayAPI.core.tcpRoute.parentRefs }}
{{- toYaml .Values.gatewayAPI.core.tcpRoute.parentRefs | nindent 4 }}
{{- else }}
{{- fail "gatewayAPI.core.tcpRoute.parentRefs is required" }}
{{- end }}
rules:
{{- if .Values.gatewayAPI.core.tcpRoute.rules }}
{{- tpl (toYaml .Values.gatewayAPI.core.tcpRoute.rules) $ | nindent 4 }}
{{- else }}
- backendRefs:
- group: ""
kind: Service
name: {{ include "gitea.service.ssh.name" . }}
port: {{ .Values.service.ssh.port }}
weight: 1
{{- end }}
{{- end }}
+1 -1
View File
@@ -22,6 +22,6 @@ spec:
{{- $testContainerSecurityContext | nindent 8 }}
{{- end }}
command: ['wget']
args: ['{{ include "gitea.fullname" . }}-http:{{ .Values.service.http.port }}']
args: ['{{ include "gitea.service.http.name" . }}:{{ .Values.service.http.port }}']
restartPolicy: Never
{{- end }}