This commit is contained in:
Younsung Lee 2026-09-27 19:01:58 +08:00 • committed by GitHub
commit 1a90503c1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 288 additions and 1 deletions

View file

@ -18,7 +18,7 @@ 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.1.3
version: 1.2.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

View file

@ -43,6 +43,11 @@ If `db.useStackgresOperator` is used (not yet implemented):
| `service.loadBalancerClass` | Optional LoadBalancer implementation class (only used when `service.type` is `LoadBalancer`) | `""` |
| `ingress.labels` | Additional labels for the Ingress resource | `{}` |
| `ingress.*` | See [values.yaml](./values.yaml) for example settings | N/A |
| `httpRoute.enabled` | Create a Gateway API `HTTPRoute` instead of (or alongside) the Ingress. Needs the Gateway API CRDs in the cluster. | `false` |
| `httpRoute.parentRefs` | Gateways the route attaches to. Required when `httpRoute.enabled` is `true`. | `[]` |
| `httpRoute.hostnames` | Hostnames the route answers on. Empty inherits every hostname of the parent listener. | `[]` |
| `httpRoute.rules` | Routing rules. Every rule is backed by this chart's Service; `matches`, `filters`, and `timeouts` are passed through as written. | One `PathPrefix` `/` rule |
| `httpRoute.*` | See [values.yaml](./values.yaml) for example settings | N/A |
| `proxyConfigMap.create` | When `true`, render a ConfigMap from `.Values.proxy_config` and mount it. | `true` |
| `proxyConfigMap.name` | When `create=false`, name of the existing ConfigMap to mount. | `""` |
| `proxyConfigMap.key` | Key in the ConfigMap that contains the proxy config file. | `"config.yaml"` |

View file

@ -5,6 +5,18 @@
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- end }}
{{- if .Values.httpRoute.enabled }}
{{- if .Values.httpRoute.hostnames }}
{{- range .Values.httpRoute.hostnames }}
Served by the parent Gateway on: {{ . }}
{{- end }}
{{- else }}
The HTTPRoute inherits the hostnames of its parent Gateway listener:
kubectl get --namespace {{ .Release.Namespace }} httproute {{ include "litellm.fullname" . }} -o jsonpath="{.spec.parentRefs}"
{{- end }}
{{- end }}
{{- if or .Values.ingress.enabled .Values.httpRoute.enabled }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "litellm.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")

View file

@ -0,0 +1,49 @@
{{- if .Values.httpRoute.enabled -}}
{{- $fullName := include "litellm.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if not .Values.httpRoute.parentRefs }}
{{- fail "httpRoute.parentRefs must name at least one Gateway when httpRoute.enabled is true. An HTTPRoute with no parent is never attached to a listener, so it accepts no traffic." }}
{{- end }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ $fullName }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "litellm.labels" . | nindent 4 }}
{{- with .Values.httpRoute.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- toYaml .Values.httpRoute.parentRefs | nindent 4 }}
{{- with .Values.httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range .Values.httpRoute.rules }}
- backendRefs:
- group: ''
kind: Service
name: {{ $fullName }}
port: {{ $svcPort }}
weight: 1
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .matches }}
matches:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .timeouts }}
timeouts:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,182 @@
suite: HTTPRoute Configuration Tests
templates:
- httproute.yaml
tests:
- it: should not create an HTTPRoute by default
asserts:
- hasDocuments:
count: 0
- it: should fail when enabled without parentRefs
set:
httpRoute.enabled: true
asserts:
- failedTemplate:
errorMessage: httpRoute.parentRefs must name at least one Gateway when httpRoute.enabled is true. An HTTPRoute with no parent is never attached to a listener, so it accepts no traffic.
- it: should create a v1 HTTPRoute routing / to the chart Service
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
asserts:
- hasDocuments:
count: 1
- isKind:
of: HTTPRoute
- isAPIVersion:
of: gateway.networking.k8s.io/v1
- equal:
path: metadata.name
value: RELEASE-NAME-litellm
- equal:
path: spec.parentRefs[0].name
value: external
- equal:
path: spec.rules[0].matches[0].path.type
value: PathPrefix
- equal:
path: spec.rules[0].matches[0].path.value
value: /
- equal:
path: spec.rules[0].backendRefs[0].kind
value: Service
- equal:
path: spec.rules[0].backendRefs[0].name
value: RELEASE-NAME-litellm
- equal:
path: spec.rules[0].backendRefs[0].port
value: 4000
- notExists:
path: spec.hostnames
- it: should point the backendRef at the overridden service port
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
service.port: 8080
asserts:
- equal:
path: spec.rules[0].backendRefs[0].port
value: 8080
- it: should name the route and its backend after fullnameOverride
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
fullnameOverride: litellm-proxy
asserts:
- equal:
path: metadata.name
value: litellm-proxy
- equal:
path: spec.rules[0].backendRefs[0].name
value: litellm-proxy
- it: should keep the namespace and sectionName of every parentRef
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
namespace: gateway-system
sectionName: https
- name: internal
asserts:
- equal:
path: spec.parentRefs[0].namespace
value: gateway-system
- equal:
path: spec.parentRefs[0].sectionName
value: https
- equal:
path: spec.parentRefs[1].name
value: internal
- notExists:
path: spec.parentRefs[1].namespace
- it: should render the configured hostnames
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
httpRoute.hostnames:
- api.example.local
- api2.example.local
asserts:
- equal:
path: spec.hostnames[0]
value: api.example.local
- equal:
path: spec.hostnames[1]
value: api2.example.local
- it: should back every rule with the chart Service and keep matches, filters, and timeouts
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
httpRoute.rules:
- matches:
- path:
type: PathPrefix
value: /v1
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: X-Forwarded-Proto
value: https
- matches:
- path:
type: Exact
value: /health/readiness
timeouts:
request: 10s
backendRequest: 2s
asserts:
- lengthEqual:
path: spec.rules
count: 2
- equal:
path: spec.rules[0].matches[0].path.value
value: /v1
- equal:
path: spec.rules[0].filters[0].requestHeaderModifier.set[0].name
value: X-Forwarded-Proto
- equal:
path: spec.rules[0].backendRefs[0].name
value: RELEASE-NAME-litellm
- notExists:
path: spec.rules[0].timeouts
- equal:
path: spec.rules[1].matches[0].path.type
value: Exact
- equal:
path: spec.rules[1].timeouts.request
value: 10s
- equal:
path: spec.rules[1].backendRefs[0].port
value: 4000
- it: should carry the chart labels plus any custom labels and annotations
set:
httpRoute.enabled: true
httpRoute.parentRefs:
- name: external
httpRoute.labels:
custom-label: "true"
httpRoute.annotations:
custom-annotation: "value"
asserts:
- equal:
path: metadata.labels["app.kubernetes.io/name"]
value: litellm
- equal:
path: metadata.labels["custom-label"]
value: "true"
- equal:
path: metadata.annotations["custom-annotation"]
value: "value"

View file

@ -132,6 +132,45 @@ ingress:
# hosts:
# - chart-example.local
# Gateway API route, as an alternative to ingress.* on clusters served by a
# Gateway rather than an ingress controller. Independent of ingress.enabled:
# both can be on during a migration. The Gateway itself is not created here;
# it is usually owned by the platform team and shared across namespaces, so
# this chart only attaches a route to it. Needs the Gateway API CRDs installed
# in the cluster.
httpRoute:
enabled: false
labels: {}
annotations: {}
# The Gateway(s) this route attaches to. Required when enabled: a route with
# no parent is never attached to a listener, so it accepts no traffic. Set
# `namespace` for a Gateway outside the release namespace, whose listener
# must also allow routes from this namespace.
parentRefs: []
# - name: example-gateway
# namespace: example-gateway-namespace
# sectionName: https
# Hostnames this route answers on. Each has to match a hostname the parent
# listener serves. Leave empty to inherit every hostname of the listener.
hostnames: []
# - api.example.local
# Routing rules. Every rule is backed by this chart's Service on
# service.port; matches, filters, and timeouts are passed through as written.
rules:
- matches:
- path:
type: PathPrefix
value: /
# filters:
# - type: RequestHeaderModifier
# requestHeaderModifier:
# add:
# - name: X-Custom-Header
# value: custom-value
# timeouts:
# request: 10s
# backendRequest: 2s
# masterkey: changeit
# if set, use this secret for the master key; otherwise, autogenerate a new one