initial commit
All checks were successful
Build and Publish TechDocs (Helm Chart Resource) / build-and-publish-helm-chart (push) Successful in 1m12s

Change-Id: I8c7efecb9159f9025c139ba383cf1a5ae84ed88f
This commit is contained in:
Scaffolder
2026-04-23 11:59:00 +00:00
commit a3a22627d1
60 changed files with 3311 additions and 0 deletions

21
deploy/.helmignore Normal file
View File

@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
.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/

39
deploy/Chart.yaml Normal file
View File

@@ -0,0 +1,39 @@
# Copyright 2026 HAProxy Technologies LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
apiVersion: v2
name: haproxy-unified-gateway
description: A Helm chart for HAProxy Unified Gateway - Kubernetes Gateway API Controller
type: application
version: 1.0.1
appVersion: 1.0.1
kubeVersion: ">=1.26.0-0"
keywords:
- haproxy
- gateway-api
- gateway
- load-balancer
home: https://github.com/haproxytech/helm-charts/tree/main/haproxy-unified-gateway
sources:
- https://github.com/haproxytech/haproxy-unified-gateway
icon: https://raw.githubusercontent.com/haproxytech/helm-charts/main/kubernetes-ingress/chart-icon.png
maintainers:
- name: Zlatko Bratkovic
email: zbratkovic@haproxy.com
- name: Dinko Korunic
email: dkorunic@haproxy.com
annotations:
artifacthub.io/license: Apache-2.0
artifacthub.io/changes: |-
- Use HAProxy Unified Gateway 1.0.1 version for base image

495
deploy/README.md Normal file
View File

@@ -0,0 +1,495 @@
# ![HAProxy](https://github.com/haproxytech/kubernetes-ingress/raw/master/assets/images/haproxy-weblogo-210x49.png "HAProxy")
## HAProxy Unified Gateway
A Kubernetes Gateway API controller powered by HAProxy. HAProxy Unified Gateway (HUG) implements the [Gateway API](https://gateway-api.sigs.k8s.io/) specification to provide advanced traffic management capabilities.
## Introduction
This chart bootstraps a HAProxy Unified Gateway deployment/daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
### Prerequisites
- Kubernetes 1.26+
- Helm 3.6+ (recommended 3.7+)
## Before you begin
### Setting up a Kubernetes Cluster
The quickest way to setup a Kubernetes cluster is with [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service/), [AWS Elastic Kubernetes Service](https://aws.amazon.com/eks/) or [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) using their respective quick-start guides.
For setting up Kubernetes on other cloud platforms or bare-metal servers refer to the Kubernetes [getting started guide](http://kubernetes.io/docs/getting-started-guides/).
### Install Helm
Get the latest [Helm release](https://github.com/helm/helm#install).
### Adding Helm chart repo
Once you have Helm installed, add the haproxytech Chart Repository as follows:
```console
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo update
```
## Installing the chart
To install the chart with Helm v3 as _my-release_ deployment:
```console
helm install my-release haproxytech/haproxy-unified-gateway
```
### Installing with unique name
To auto-generate controller and its resources names when installing, use the following:
```console
helm install haproxytech/haproxy-unified-gateway \
--generate-name
```
### Installing from a private registry
To install the chart using a private registry for controller into a separate namespace _prod_.
**_NOTE_**: Helm v3 requires namespace to be precreated (eg. with `kubectl create namespace prod`)
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--namespace prod \
--set controller.image.tag=SOMETAG \
--set controller.imagePullSecrets[0].name=my-pull-secret
```
### Using values from YAML file
As opposed to using many `--set` invocations, much simpler approach is to define value overrides in a separate YAML file and specify them when invoking Helm:
_myhug.yaml_:
```yaml
controller:
kind: DaemonSet
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
```
And invoking Helm becomes:
```console
helm install my-release -f myhug.yaml haproxytech/haproxy-unified-gateway
```
### Installing as DaemonSet
Default controller mode is [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/), but it is possible to use [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) as well:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.kind=DaemonSet
```
### Installing with host networking (DaemonSet)
When using DaemonSet mode, you can enable host networking and host ports:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.kind=DaemonSet \
--set controller.daemonset.useHostNetwork=true \
--set controller.dnsPolicy=ClusterFirstWithHostNet
```
### Installing with service annotations
On some environments like EKS and GKE there might be a need to pass service annotations. Syntax can become a little tedious however:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.service.type=LoadBalancer \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-internal"="0.0.0.0/0" \
--set controller.service.annotations."service\.beta\.kubernetes\.io/aws-load-balancer-cross-zone-load-balancing-enabled"="true"
```
**_NOTE_**: With helm `--set` it is needed to put quotes and escape dots in the annotation key and commas in the value string.
### Installing with Horizontal Pod Autoscaler (HPA)
[HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) automatically scales number of replicas in Deployment and adjusts replica count for the controller:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.autoscaling.enabled=true
```
### Enabling Prometheus monitoring
HUG exposes two separate metrics endpoints:
- **`stat`** (port 31024) — HAProxy native metrics (`haproxy_*` prefix): connections, request rates, backend health, latency, error codes
- **`metrics`** (port 31060) — HUG controller metrics (`hug_*` prefix): event batch processing, config generation, cert/map operations, HAProxy reloads
The chart supports both [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md) and [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/design.md#podmonitor) for Prometheus Operator integration. These are mutually exclusive — enable only one. By default, both endpoints are scraped.
**Note:** Requires Prometheus Operator installed in the cluster. The `monitoring.coreos.com/v1` API must be available.
#### Metrics authentication
The controller metrics endpoint (`metrics` port) supports three authentication modes via `controller.metricsAuth`:
| Mode | Default | Protocol | Description |
| --- | --- | --- | --- |
| `kube-rbac` | **yes** | HTTPS | Kubernetes TokenReview/SubjectAccessReview — Prometheus authenticates with its ServiceAccount token |
| `none` | | HTTP | No authentication |
| `basic` | | HTTPS | HTTP Basic Authentication with username/password |
#### Default setup (kube-rbac)
By default the chart uses `kube-rbac` authentication. The controller serves metrics over HTTPS and validates bearer tokens via the Kubernetes API. To set it up:
**Step 1.** Create a ClusterRole that grants access to the `/metrics` endpoint and bind it to the Prometheus ServiceAccount:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: hug-metrics-reader
rules:
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: hug-metrics-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: hug-metrics-reader
subjects:
- kind: ServiceAccount
name: prometheus # adjust to your Prometheus SA name
namespace: monitoring # adjust to your Prometheus namespace
```
**Step 2.** Enable the ServiceMonitor (or PodMonitor). The default endpoints are pre-configured for kube-rbac — `stat` uses plain HTTP, `metrics` uses HTTPS with the Prometheus pod's ServiceAccount token:
```yaml
controller:
serviceMonitor:
enabled: true
extraLabels:
release: prometheus # match your Prometheus serviceMonitorSelector
```
That's it. The default `values.yaml` endpoints already include the correct HTTPS + bearer token configuration for the `metrics` port:
```yaml
# Default endpoints (already set in values.yaml):
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
```
#### Using no authentication
To disable metrics authentication:
```yaml
controller:
metricsAuth: none
serviceMonitor:
enabled: true
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: http
interval: 30s
```
#### Using basic authentication
```yaml
controller:
metricsAuth: basic
extraArgs:
- --metrics-basic-auth-user=prometheus
- --metrics-basic-auth-password=secret
serviceMonitor:
enabled: true
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
basicAuth:
username:
name: hug-metrics-basic-auth
key: username
password:
name: hug-metrics-basic-auth
key: password
```
#### Using PodMonitor instead of ServiceMonitor
PodMonitor scrapes pods directly without creating an extra metrics Service. Replace `serviceMonitor` with `podMonitor` in any of the examples above:
```yaml
controller:
podMonitor:
enabled: true
extraLabels:
release: prometheus
```
### Configuring HugConf
The chart creates a HugConf custom resource for controller configuration. You can customize logging, and optionally reference Global and Defaults custom resources:
```yaml
hugconf:
logging:
defaultLevel: Debug
categoryLevelList:
- category: "gate"
level: "Debug"
- category: "k8s"
level: "Info"
# Reference a Global CR for HAProxy global section customization
globalRef:
group: gate.v3.haproxy.org
kind: Global
name: global
# Reference a Defaults CR for HAProxy defaults section customization
defaultsRef:
group: gate.v3.haproxy.org
kind: Defaults
name: haproxytech
```
The Global and Defaults CRDs are automatically installed by the CRD job. When a `globalRef` or `defaultsRef` is set, the controller uses the referenced CR to configure the HAProxy global/defaults sections. When removed, built-in defaults are restored.
### Adding extra ports
By default the chart exposes four container ports: `http` (31080), `https` (31443), `stat` (31024) and `metrics` (31060). Additional ports can be added in two places:
1. **`controller.containerPort`** — exposes the port on the container (pod spec)
2. **`controller.service.extraPorts`** — exposes the port on the Service
#### Using `--set` flags
To add a container port only (e.g. for a sidecar or internal use):
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.containerPort.custom=8080
```
To also expose it on the Service:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set controller.containerPort.custom=8080 \
--set controller.service.extraPorts[0].name=custom \
--set controller.service.extraPorts[0].port=8080 \
--set controller.service.extraPorts[0].targetPort=8080 \
--set controller.service.extraPorts[0].protocol=TCP
```
#### Using a values file
For multiple extra ports, a values file is cleaner:
```yaml
controller:
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
grpc: 9090
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP
- name: grpc
port: 9090
targetPort: 9090
protocol: TCP
```
#### DaemonSet with host ports
For DaemonSet mode with host ports, also add matching entries in `controller.daemonset.hostPorts`:
```yaml
controller:
kind: DaemonSet
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
daemonset:
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024
custom: 8080
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP
```
### Passing extra arguments
Additional controller flags can be passed via `extraArgs`:
```yaml
controller:
extraArgs:
- --controller-name=gate.haproxy.org/hug
- --namespaces=default,production
- --leader-election-enabled
```
#### Available controller flags
| Flag | Default | Description |
| --- | --- | --- |
| `--controller-name` | `gate.haproxy.org/hug` | `spec.controllerName` GatewayClass selector |
| `--namespaces` | | Comma-separated list of namespaces to monitor |
| `--ipv4-bind-address` | | IPv4 address to bind to |
| `--ipv6-bind-address` | | IPv6 address to bind to |
| `--disable-ipv4` | `false` | Disable IPv4 support |
| `--disable-ipv6` | `false` | Disable IPv6 support |
| `--stats-port` | `1024` | Port for HAProxy stats |
| `--controller-port` | `31060` | Port for controller metrics (prometheus) |
| `--log-type` | `json` | Log output type (`text` or `json`) |
| `--sync-period` | `0` | Period at which the controller computes HAProxy configuration (e.g. `5s`, `1m`) |
| `--startup-sync-period` | `0` | Startup period for HAProxy config computation |
| `--cache-resync-period` | `0` | Controller-runtime manager cache SyncPeriod (defaults to 10 hours if not set) |
| `--leader-election-enabled` | `false` | Enable leader election |
| `--add-stats-port` | `true` | Add stats port bind to existing stats frontend |
| `--metrics-auth` | `none` | Metrics endpoint auth mode: `none`, `kube-rbac`, `basic` |
| `--metrics-basic-auth-user` | | Basic auth username (when `--metrics-auth=basic`) |
| `--metrics-basic-auth-password` | | Basic auth password (when `--metrics-auth=basic`) |
**Note:** The `--hugconf-crd` flag is set automatically by the chart via the `hugconfCrd` helper. The `--job-check-crd` and `--job-gwapi` flags are used internally by the CRD/Gateway API installation jobs.
### Installing with KEDA autoscaling
[KEDA](https://keda.sh/) provides event-driven autoscaling. It is mutually exclusive with HPA — when KEDA is enabled, HPA is automatically disabled even if `autoscaling.enabled` is set to `true`.
```yaml
controller:
keda:
enabled: true
minReplicas: 2
maxReplicas: 20
pollingInterval: 30
cooldownPeriod: 300
restoreToOriginalReplicaCount: false
scaledObject:
annotations: {}
triggers:
- type: prometheus
metadata:
serverAddress: http://<prometheus-host>:9090
metricName: haproxy_process_idle_time_percent
threshold: '50'
query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))
```
Optional advanced configuration:
```yaml
controller:
keda:
enabled: true
# ...triggers, minReplicas, maxReplicas...
fallback:
failureThreshold: 3
replicas: 5
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 300
```
### Disabling CRD/Gateway API installation jobs
By default, the chart includes Helm hook jobs that install HUG CRDs and Gateway API CRDs. To disable them:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--set crdjob.enabled=false \
--set gwapijob.enabled=false
```
## Upgrading the chart
To upgrade the _my-release_ deployment:
```console
helm upgrade my-release haproxytech/haproxy-unified-gateway
```
## Uninstalling the chart
To uninstall/delete the _my-release_ deployment:
```console
helm delete my-release
```
## Debugging
It is possible to generate a set of YAML files for testing/debugging:
```console
helm install my-release haproxytech/haproxy-unified-gateway \
--debug \
--dry-run
```
## Contributing
We welcome all contributions. Please refer to [guidelines](../CONTRIBUTING.md) on how to make a contribution.

View File

@@ -0,0 +1,12 @@
controller:
kind: DaemonSet
service:
type: NodePort
http:
port: 8080
targetPort: 8080
nodePort: 30080
https:
port: 8443
targetPort: 8443
nodePort: 30443

View File

@@ -0,0 +1,2 @@
controller:
kind: DaemonSet

View File

@@ -0,0 +1,5 @@
controller:
kind: DaemonSet
extraArgs:
- --controller-name=gate.haproxy.org/hug
- --namespaces=default

View File

@@ -0,0 +1,7 @@
controller:
kind: DaemonSet
extraEnvs:
- name: TEST_STR1
value: foo
- name: TEST_STR2
value: baz

View File

@@ -0,0 +1,21 @@
## Test: DaemonSet with extra container and service ports, including host ports
controller:
kind: DaemonSet
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
daemonset:
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024
custom: 8080
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP

View File

@@ -0,0 +1,8 @@
controller:
kind: DaemonSet
daemonset:
useHostPort: true
hostPorts:
http: 80
https: 443
stat: 1024

View File

@@ -0,0 +1,5 @@
controller:
kind: DaemonSet
service:
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0

View File

@@ -0,0 +1,7 @@
controller:
kind: DaemonSet
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1

View File

@@ -0,0 +1,11 @@
controller:
service:
type: NodePort
http:
port: 8080
targetPort: 8080
nodePort: 30080
https:
port: 8443
targetPort: 8443
nodePort: 30443

View File

@@ -0,0 +1 @@
#

View File

@@ -0,0 +1,4 @@
crdjob:
enabled: false
gwapijob:
enabled: false

View File

@@ -0,0 +1,4 @@
controller:
extraArgs:
- --controller-name=gate.haproxy.org/hug
- --namespaces=default

View File

@@ -0,0 +1,6 @@
controller:
extraEnvs:
- name: TEST_STR1
value: foo
- name: TEST_STR2
value: baz

View File

@@ -0,0 +1,14 @@
## Test: Deployment with extra container and service ports
controller:
kind: Deployment
containerPort:
http: 31080
https: 31443
stat: 31024
custom: 8080
service:
extraPorts:
- name: custom
port: 8080
targetPort: 8080
protocol: TCP

View File

@@ -0,0 +1,6 @@
controller:
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80

View File

@@ -0,0 +1,8 @@
hugconf:
logging:
defaultLevel: Debug
categoryLevelList:
- category: "gate"
level: "Debug"
- category: "k8s"
level: "Info"

View File

@@ -0,0 +1,34 @@
controller:
keda:
enabled: true
minReplicas: 1
maxReplicas: 10
pollingInterval: 15
cooldownPeriod: 600
restoreToOriginalReplicaCount: true
scaledObject:
annotations: {}
fallback:
failureThreshold: 3
replicas: 5
horizontalPodAutoscalerConfig:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 300
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: haproxy_process_idle_time_percent
threshold: '50'
query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))
# HPA should be ignored when KEDA is enabled
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
targetCPUUtilizationPercentage: 80

View File

@@ -0,0 +1,18 @@
controller:
keda:
enabled: true
minReplicas: 2
maxReplicas: 20
pollingInterval: 30
cooldownPeriod: 300
restoreToOriginalReplicaCount: false
scaledObject:
annotations:
test-annotation: "test-value"
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: haproxy_process_idle_time_percent
threshold: '50'
query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))

View File

@@ -0,0 +1,14 @@
## Test: Deployment with metricsAuth=none (plain HTTP controller metrics)
controller:
metricsAuth: none
serviceMonitor:
enabled: true
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: http
interval: 30s

View File

@@ -0,0 +1,5 @@
controller:
replicaCount: 2
podDisruptionBudget:
enabled: true
minAvailable: 1

View File

@@ -0,0 +1,10 @@
controller:
podMonitor:
enabled: true
extraLabels:
release: prometheus
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s

View File

@@ -0,0 +1,18 @@
## Test: Deployment with ServiceMonitor (both stat and controller metrics endpoints)
controller:
serviceMonitor:
enabled: true
extraLabels:
release: prometheus
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

View File

@@ -0,0 +1,6 @@
controller:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1

View File

@@ -0,0 +1,51 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
HAProxy Unified Gateway has been installed.
{{- if .Values.controller.service.enabled }}
The controller is exposed via a {{ .Values.controller.service.type }} Service:
- HTTP: {{ .Values.controller.service.http.port }}
- HTTPS: {{ .Values.controller.service.https.port }}
- Stats: {{ .Values.controller.service.stat.port }}
{{- if eq .Values.controller.service.type "NodePort" }}
Access the gateway using your node IP and the configured NodePort:
export NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="ExternalIP")].address}')
echo "HTTP: http://$NODE_IP:{{ .Values.controller.service.http.nodePort }}"
echo "HTTPS: https://$NODE_IP:{{ .Values.controller.service.https.nodePort }}"
{{- else if eq .Values.controller.service.type "LoadBalancer" }}
It may take a few minutes for the LoadBalancer IP to be available.
Watch the status with:
kubectl get svc {{ include "haproxy-unified-gateway.fullname" . }} -n {{ include "haproxy-unified-gateway.namespace" . }} -w
{{- end }}
{{- end }}
{{- if .Values.crdjob.enabled }}
A post-install/pre-upgrade Job will install/update the HUG CRDs automatically.
{{- end }}
{{- if .Values.gwapijob.enabled }}
A post-install/pre-upgrade Job will install Gateway API CRDs (v{{ .Values.gwapijob.version }}).
{{- end }}
To check the controller status:
kubectl get pods -n {{ include "haproxy-unified-gateway.namespace" . }} -l "{{ include "haproxy-unified-gateway.selectorLabels" . | replace "\n" "," }}"
For more information, visit: https://github.com/haproxytech/haproxy-unified-gateway

View File

@@ -0,0 +1,174 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{/*
Expand the name of the chart.
*/}}
{{- define "haproxy-unified-gateway.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "haproxy-unified-gateway.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 "haproxy-unified-gateway.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Namespace to use.
*/}}
{{- define "haproxy-unified-gateway.namespace" -}}
{{- default .Release.Namespace .Values.namespaceOverride }}
{{- end }}
{{/*
Selector labels.
*/}}
{{- define "haproxy-unified-gateway.selectorLabels" -}}
app.kubernetes.io/name: {{ include "haproxy-unified-gateway.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Helm chart metadata labels.
*/}}
{{- define "haproxy-unified-gateway.helmChartLabels" -}}
helm.sh/chart: {{ include "haproxy-unified-gateway.chart" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Common labels (selector + chart metadata).
*/}}
{{- define "haproxy-unified-gateway.labels" -}}
{{ include "haproxy-unified-gateway.selectorLabels" . }}
{{ include "haproxy-unified-gateway.helmChartLabels" . }}
{{- end }}
{{/*
ServiceAccount name.
*/}}
{{- define "haproxy-unified-gateway.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "haproxy-unified-gateway.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Controller image.
*/}}
{{- define "haproxy-unified-gateway.image" -}}
{{- $tag := default .Chart.AppVersion .Values.controller.image.tag -}}
{{- printf "%s:%s" .Values.controller.image.repository $tag }}
{{- end }}
{{/*
CRD Job ServiceAccount/RBAC name.
*/}}
{{- define "haproxy-unified-gateway.crdjob.saName" -}}
{{- printf "%s-crdjob" (include "haproxy-unified-gateway.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Metrics Service name.
*/}}
{{- define "haproxy-unified-gateway.metricsServiceName" -}}
{{- printf "%s-metrics" (include "haproxy-unified-gateway.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
HugConf cleanup Job name.
*/}}
{{- define "haproxy-unified-gateway.hugconfCleanup.fullname" -}}
{{- printf "%s-hugconf-cleanup" (include "haproxy-unified-gateway.fullname" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
CRD Job labels.
*/}}
{{- define "haproxy-unified-gateway.crdjobLabels" -}}
{{ include "haproxy-unified-gateway.helmChartLabels" . }}
app.kubernetes.io/name: {{ include "haproxy-unified-gateway.name" . }}-crdjob
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
CRD Job fullname (includes revision for uniqueness).
*/}}
{{- define "haproxy-unified-gateway.crdjob.fullname" -}}
{{- printf "%s-crdjob-%d" (include "haproxy-unified-gateway.fullname" .) .Release.Revision | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Gateway API Job labels.
*/}}
{{- define "haproxy-unified-gateway.gwapijobLabels" -}}
{{ include "haproxy-unified-gateway.helmChartLabels" . }}
app.kubernetes.io/name: {{ include "haproxy-unified-gateway.name" . }}-gwapijob
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Gateway API Job fullname (includes revision for uniqueness).
*/}}
{{- define "haproxy-unified-gateway.gwapijob.fullname" -}}
{{- printf "%s-gwapijob-%d" (include "haproxy-unified-gateway.fullname" .) .Release.Revision | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
ServiceMonitor name.
*/}}
{{- define "haproxy-unified-gateway.serviceMonitorName" -}}
{{- default (include "haproxy-unified-gateway.fullname" .) .Values.controller.serviceMonitor.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
PodMonitor name.
*/}}
{{- define "haproxy-unified-gateway.podMonitorName" -}}
{{- default (include "haproxy-unified-gateway.fullname" .) .Values.controller.podMonitor.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
HugConf CRD reference path (namespace/name).
*/}}
{{- define "haproxy-unified-gateway.hugconfCrd" -}}
{{- if .Values.controller.hugconfCrd }}
{{- .Values.controller.hugconfCrd }}
{{- else }}
{{- printf "%s/%s" (include "haproxy-unified-gateway.namespace" .) .Values.hugconf.name }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,138 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
rules:
- apiGroups:
- "apiextensions.k8s.io"
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- update
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- services
- namespaces
- events
- serviceaccounts
verbs:
- get
- list
- watch
- create
- patch
- update
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
- create
- patch
- update
- apiGroups:
- "discovery.k8s.io"
resources:
- endpointslices
verbs:
- get
- list
- watch
- apiGroups:
- "apps"
resources:
- replicasets
- deployments
- daemonsets
verbs:
- get
- list
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses
- gateways
- httproutes
- referencegrants
- grpcroutes
- tlsroutes
verbs:
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- gatewayclasses/status
- gateways/status
- httproutes/status
- referencegrants/status
- grpcroutes/status
- tlsroutes/status
verbs:
- get
- update
- patch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- get
- update
- apiGroups:
- gate.v3.haproxy.org
resources:
- huggates
- hugconfs
- backends
- globals
- defaults
verbs:
- get
- list
- watch
# Required for kube-rbac metrics auth (TokenReview + SubjectAccessReview)
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
{{- end }}

View File

@@ -0,0 +1,32 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "haproxy-unified-gateway.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,72 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if or .Values.crdjob.enabled .Values.gwapijob.enabled }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
rules:
- apiGroups:
- "apiextensions.k8s.io"
resources:
- customresourcedefinitions
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
{{- end }}

View File

@@ -0,0 +1,96 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.crdjob.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "haproxy-unified-gateway.crdjob.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
"argocd.argoproj.io/hook": PostSync
{{- with .Values.crdjob.podAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.crdjob.ttlSecondsAfterFinished }}
ttlSecondsAfterFinished: {{ . }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.crdjobLabels" . | nindent 8 }}
{{- with .Values.crdjob.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: crdjob
{{- if .Values.crdjob.image.repository }}
image: {{ printf "%s:%s" .Values.crdjob.image.repository (default .Chart.AppVersion .Values.crdjob.image.tag) }}
{{- else }}
image: {{ include "haproxy-unified-gateway.image" . }}
{{- end }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /usr/local/sbin/hug
- --job-check-crd
{{- with .Values.crdjob.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.crdjob.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.crdjob.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.crdjob.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
backoffLimit: 0
{{- end }}

View File

@@ -0,0 +1,185 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if eq .Values.controller.kind "DaemonSet" }}
{{- $useHostNetwork := .Values.controller.daemonset.useHostNetwork -}}
{{- $useHostPort := .Values.controller.daemonset.useHostPort -}}
{{- $hostPorts := .Values.controller.daemonset.hostPorts -}}
{{- $hostIP := .Values.controller.daemonset.hostIP -}}
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- with .Values.controller.strategy }}
updateStrategy:
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 8 }}
{{- with .Values.controller.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
{{- end }}
{{- with .Values.controller.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
{{- if $useHostNetwork }}
hostNetwork: true
{{- end }}
{{- with .Values.controller.dnsPolicy }}
dnsPolicy: {{ . }}
{{- end }}
{{- with .Values.controller.dnsConfig }}
dnsConfig:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ include "haproxy-unified-gateway.name" . }}
image: {{ include "haproxy-unified-gateway.image" . }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
args:
{{- if or .Values.hugconf.create .Values.controller.hugconfCrd }}
- --hugconf-crd={{ include "haproxy-unified-gateway.hugconfCrd" . }}
{{- end }}
{{- with .Values.controller.metricsAuth }}
- --metrics-auth={{ . }}
{{- end }}
{{- range .Values.controller.extraArgs }}
- {{ . }}
{{- end }}
ports:
{{- range $key, $value := .Values.controller.containerPort }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- if and $useHostPort (index $hostPorts $key) }}
hostPort: {{ index $hostPorts $key }}
{{- end }}
{{- if $hostIP }}
hostIP: {{ $hostIP }}
{{- end }}
{{- end }}
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{- with .Values.controller.extraEnvs }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: {{ .Values.controller.allowPrivilegeEscalation }}
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
{{- with .Values.controller.seccompProfile }}
seccompProfile:
{{- toYaml . | nindent 14 }}
{{- end }}
{{- end }}
{{- with .Values.controller.extraVolumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.extraContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.extraVolumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,175 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if eq .Values.controller.kind "Deployment" }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if not .Values.controller.autoscaling.enabled }}
replicas: {{ .Values.controller.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- with .Values.controller.strategy }}
strategy:
{{- toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 8 }}
{{- with .Values.controller.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
{{- end }}
{{- with .Values.controller.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
{{- with .Values.controller.dnsPolicy }}
dnsPolicy: {{ . }}
{{- end }}
{{- with .Values.controller.dnsConfig }}
dnsConfig:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.initContainers }}
initContainers:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ include "haproxy-unified-gateway.name" . }}
image: {{ include "haproxy-unified-gateway.image" . }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
args:
{{- if or .Values.hugconf.create .Values.controller.hugconfCrd }}
- --hugconf-crd={{ include "haproxy-unified-gateway.hugconfCrd" . }}
{{- end }}
{{- with .Values.controller.metricsAuth }}
- --metrics-auth={{ . }}
{{- end }}
{{- range .Values.controller.extraArgs }}
- {{ . }}
{{- end }}
ports:
{{- range $key, $value := .Values.controller.containerPort }}
- name: {{ $key }}
containerPort: {{ $value }}
protocol: TCP
{{- end }}
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
{{- with .Values.controller.extraEnvs }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.startupProbe }}
startupProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.controller.unprivileged }}
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: {{ .Values.controller.allowPrivilegeEscalation }}
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
{{- with .Values.controller.seccompProfile }}
seccompProfile:
{{- toYaml . | nindent 14 }}
{{- end }}
{{- end }}
{{- with .Values.controller.extraVolumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.controller.extraContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.extraVolumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,96 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.gwapijob.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "haproxy-unified-gateway.gwapijob.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.gwapijobLabels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
"argocd.argoproj.io/hook": PostSync
{{- with .Values.gwapijob.podAnnotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.gwapijob.ttlSecondsAfterFinished }}
ttlSecondsAfterFinished: {{ . }}
{{- end }}
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.gwapijobLabels" . | nindent 8 }}
{{- with .Values.gwapijob.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.crdjob.saName" . }}
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: gwapijob
{{- if .Values.gwapijob.image.repository }}
image: {{ printf "%s:%s" .Values.gwapijob.image.repository (default .Chart.AppVersion .Values.gwapijob.image.tag) }}
{{- else }}
image: {{ include "haproxy-unified-gateway.image" . }}
{{- end }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /usr/local/sbin/hug
- --job-gwapi={{ .Values.gwapijob.version }}
{{- with .Values.gwapijob.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.gwapijob.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.gwapijob.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.gwapijob.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
backoffLimit: 0
{{- end }}

View File

@@ -0,0 +1,53 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.controller.autoscaling.enabled (not .Values.controller.keda.enabled) }}
{{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }}
apiVersion: autoscaling/v2
{{- else }}
apiVersion: autoscaling/v2beta2
{{- end }}
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "haproxy-unified-gateway.fullname" . }}
minReplicas: {{ .Values.controller.autoscaling.minReplicas }}
maxReplicas: {{ .Values.controller.autoscaling.maxReplicas }}
metrics:
{{- if .Values.controller.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.controller.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.controller.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.controller.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,125 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.hugconf.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
rules:
- apiGroups:
- "gate.v3.haproxy.org"
resources:
- hugconfs
verbs:
- get
- delete
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
ttlSecondsAfterFinished: 60
template:
metadata:
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "haproxy-unified-gateway.hugconfCleanup.fullname" . }}
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
{{- with .Values.controller.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: hugconf-cleanup
image: {{ include "haproxy-unified-gateway.image" . }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
command:
- /bin/sh
- -c
- |
APISERVER="https://kubernetes.default.svc"
TOKEN="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
CACERT="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
wget --header="Authorization: Bearer ${TOKEN}" \
--ca-certificate="${CACERT}" \
--method=DELETE \
-q -O /dev/null \
"${APISERVER}/apis/gate.v3.haproxy.org/v3/namespaces/{{ include "haproxy-unified-gateway.namespace" . }}/hugconfs/{{ .Values.hugconf.name }}" 2>/dev/null || true
backoffLimit: 1
{{- end }}

View File

@@ -0,0 +1,45 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.hugconf.create }}
apiVersion: gate.v3.haproxy.org/v3
kind: HugConf
metadata:
name: {{ .Values.hugconf.name }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install,pre-upgrade
"helm.sh/hook-weight": "5"
"helm.sh/hook-delete-policy": before-hook-creation
"argocd.argoproj.io/hook": PostSync
spec:
logging:
defaultLevel: {{ .Values.hugconf.logging.defaultLevel | quote }}
{{- with .Values.hugconf.logging.categoryLevelList }}
categoryLevelList:
{{- toYaml . | nindent 6 }}
{{- end }}
{{- with .Values.hugconf.globalRef }}
globalRef:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.hugconf.defaultsRef }}
defaultsRef:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,57 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (eq .Values.controller.kind "Deployment") .Values.controller.keda.enabled }}
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- if .Values.controller.keda.scaledObject.annotations }}
annotations: {{ toYaml .Values.controller.keda.scaledObject.annotations | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
name: {{ include "haproxy-unified-gateway.fullname" . }}
pollingInterval: {{ .Values.controller.keda.pollingInterval }}
cooldownPeriod: {{ .Values.controller.keda.cooldownPeriod }}
minReplicaCount: {{ .Values.controller.keda.minReplicas }}
maxReplicaCount: {{ .Values.controller.keda.maxReplicas }}
triggers:
{{- with .Values.controller.keda.triggers }}
{{ toYaml . | indent 2 }}
{{ end }}
{{- with .Values.controller.keda.fallback }}
fallback:
{{ toYaml . | indent 4 }}
{{- end }}
advanced:
restoreToOriginalReplicaCount: {{ .Values.controller.keda.restoreToOriginalReplicaCount }}
{{- if .Values.controller.keda.horizontalPodAutoscalerConfig }}
horizontalPodAutoscalerConfig:
{{- if .Values.controller.keda.horizontalPodAutoscalerConfig.name }}
name: {{ .Values.controller.keda.horizontalPodAutoscalerConfig.name }}
{{- end }}
{{- if .Values.controller.keda.horizontalPodAutoscalerConfig.behavior }}
behavior:
{{ with .Values.controller.keda.horizontalPodAutoscalerConfig.behavior -}}
{{ toYaml . | indent 8 }}
{{ end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,35 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.controller.podDisruptionBudget.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- if .Values.controller.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.controller.podDisruptionBudget.minAvailable }}
{{- end }}
{{- if .Values.controller.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.controller.podDisruptionBudget.maxUnavailable }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,37 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.controller.podMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: {{ include "haproxy-unified-gateway.podMonitorName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.podMonitor.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
podMetricsEndpoints:
{{- toYaml .Values.controller.podMonitor.endpoints | nindent 4 }}
namespaceSelector:
matchNames:
- {{ include "haproxy-unified-gateway.namespace" . }}
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,81 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if (semverCompare "<1.25.0-0" .Capabilities.KubeVersion.Version) }}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled }}
{{- $useHostNetwork := false }}
{{- $useHostPort := false }}
{{- if eq .Values.controller.kind "DaemonSet" }}
{{- $useHostNetwork = .Values.controller.daemonset.useHostNetwork }}
{{- $useHostPort = .Values.controller.daemonset.useHostPort }}
{{- end }}
{{- if or (.Capabilities.APIVersions.Has "policy/v1/PodSecurityPolicy") (semverCompare ">=1.21.0-0" .Capabilities.KubeVersion.Version) }}
apiVersion: policy/v1
{{- else }}
apiVersion: policy/v1beta1
{{- end }}
kind: PodSecurityPolicy
metadata:
{{- if .Values.podSecurityPolicy.annotations }}
annotations:
{{ toYaml .Values.podSecurityPolicy.annotations | indent 4 }}
{{- end }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
name: {{ include "haproxy-unified-gateway.fullname" . }}
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
spec:
allowPrivilegeEscalation: {{ .Values.controller.allowPrivilegeEscalation }}
allowedCapabilities:
- NET_BIND_SERVICE
defaultAllowPrivilegeEscalation: false
fsGroup:
rule: MustRunAs
ranges:
- max: 65535
min: 1
hostIPC: false
{{- if $useHostNetwork }}
hostNetwork: true
{{- end }}
{{- if or $useHostPort $useHostNetwork }}
hostPorts:
{{- range $key, $value := .Values.controller.containerPort }}
- min: {{ $value }}
max: {{ $value }}
{{- end }}
{{- end }}
hostPID: false
privileged: false
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
rule: MustRunAs
ranges:
- max: 65535
min: 1
volumes:
- configMap
- downwardAPI
- secret
{{- end }}
{{- end }}

View File

@@ -0,0 +1,34 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
rules:
- apiGroups:
- "policy"
resources:
- podsecuritypolicies
verbs:
- use
resourceNames:
- {{ include "haproxy-unified-gateway.fullname" . }}
{{- end -}}

View File

@@ -0,0 +1,33 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "haproxy-unified-gateway.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
{{- end -}}

View File

@@ -0,0 +1,45 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and .Values.controller.serviceMonitor.enabled .Values.controller.service.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "haproxy-unified-gateway.metricsServiceName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.service.metrics.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.controller.service.metrics.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.controller.service.metrics.type }}
selector:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 4 }}
ports:
- name: stat
port: {{ .Values.controller.service.stat.port }}
targetPort: {{ .Values.controller.service.stat.targetPort }}
protocol: TCP
- name: metrics
port: {{ index .Values.controller.service "controller-metrics" "port" }}
targetPort: {{ index .Values.controller.service "controller-metrics" "targetPort" }}
protocol: TCP
{{- end }}

View File

@@ -0,0 +1,64 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.controller.service.enabled }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "haproxy-unified-gateway.fullname" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.service.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.controller.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.controller.service.type }}
{{- with .Values.controller.service.externalTrafficPolicy }}
externalTrafficPolicy: {{ . }}
{{- end }}
selector:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.controller.service.http.port }}
targetPort: {{ .Values.controller.service.http.targetPort }}
protocol: TCP
{{- if and (eq .Values.controller.service.type "NodePort") .Values.controller.service.http.nodePort }}
nodePort: {{ .Values.controller.service.http.nodePort }}
{{- end }}
- name: https
port: {{ .Values.controller.service.https.port }}
targetPort: {{ .Values.controller.service.https.targetPort }}
protocol: TCP
{{- if and (eq .Values.controller.service.type "NodePort") .Values.controller.service.https.nodePort }}
nodePort: {{ .Values.controller.service.https.nodePort }}
{{- end }}
- name: stat
port: {{ .Values.controller.service.stat.port }}
targetPort: {{ .Values.controller.service.stat.targetPort }}
protocol: TCP
{{- if and (eq .Values.controller.service.type "NodePort") .Values.controller.service.stat.nodePort }}
nodePort: {{ .Values.controller.service.stat.nodePort }}
{{- end }}
{{- with .Values.controller.service.extraPorts }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,29 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "haproxy-unified-gateway.serviceAccountName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,37 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.controller.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "haproxy-unified-gateway.serviceMonitorName" . }}
namespace: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
{{- with .Values.controller.serviceMonitor.extraLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
endpoints:
{{- toYaml .Values.controller.serviceMonitor.endpoints | nindent 4 }}
namespaceSelector:
matchNames:
- {{ include "haproxy-unified-gateway.namespace" . }}
selector:
matchLabels:
{{- include "haproxy-unified-gateway.selectorLabels" . | nindent 6 }}
{{- end }}

View File

@@ -0,0 +1,27 @@
{{/*
Copyright 2026 HAProxy Technologies LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/}}
{{- if .Values.namespace.create }}
apiVersion: v1
kind: Namespace
metadata:
name: {{ include "haproxy-unified-gateway.namespace" . }}
labels:
{{- include "haproxy-unified-gateway.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-1"
{{- end }}

389
deploy/values.yaml Normal file
View File

@@ -0,0 +1,389 @@
# Copyright 2026 HAProxy Technologies LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## HAProxy Unified Gateway Helm Chart - values.yaml
# -- PodSecurityPolicy configuration (deprecated in K8s 1.21, removed in 1.25)
podSecurityPolicy:
## Specify pod annotations
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl
annotations: {}
# apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default
# apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default
# seccomp.security.alpha.kubernetes.io/allowedProfileNames: runtime/default
# seccomp.security.alpha.kubernetes.io/defaultProfileName: runtime/default
enabled: false
# -- Create RBAC resources
rbac:
create: true
# -- Create a namespace (uses Helm pre-install hook)
namespace:
create: false
# -- ServiceAccount configuration
serviceAccount:
# -- Create a ServiceAccount
create: true
# -- ServiceAccount name (generated if not set)
name: ""
# -- Annotations to add to the ServiceAccount
annotations: {}
# -- Controller configuration
controller:
# -- Controller name
name: controller
# -- Container image configuration
image:
repository: docker.io/haproxytech/haproxy-unified-gateway
tag: "" # defaults to appVersion
pullPolicy: IfNotPresent
# -- Image pull secrets
imagePullSecrets: []
# -- Deployment or DaemonSet pod mode
# ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
# ref: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
kind: Deployment # can be 'Deployment' or 'DaemonSet'
# -- Number of replicas (only for Deployment mode)
replicaCount: 1
# -- HugConf CRD reference (namespace/name)
# If empty, defaults to "<release-namespace>/hugconf"
hugconfCrd: ""
# -- Metrics authentication mode for the controller metrics endpoint (port 31060)
# Supported values: "none", "kube-rbac", "basic"
# - none: HTTP, no authentication
# - kube-rbac: HTTPS with Kubernetes TokenReview/SubjectAccessReview
# - basic: HTTPS with HTTP Basic Authentication (set credentials via extraArgs)
metricsAuth: kube-rbac
# -- Extra arguments to pass to the controller
extraArgs: []
# -- Container ports
containerPort:
http: 31080
https: 31443
stat: 31024
metrics: 31060
# -- Resource requests and limits
resources:
limits:
memory: 2560Mi
requests:
memory: 2048Mi
## Running container without root privileges
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
unprivileged: true
## Privilege escalation
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
allowPrivilegeEscalation: false
## Restricts container syscalls
## ref: https://kubernetes.io/docs/tutorials/security/seccomp/
## Supported types: RuntimeDefault, Localhost, Unconfined
## Set to empty ({}) to disable seccomp profile
seccompProfile:
type: RuntimeDefault
# localhostProfile: my-profiles/profile.json # only for type: Localhost
# -- Pod-level security context
podSecurityContext: {}
# -- Liveness probe configuration
livenessProbe: {}
# -- Readiness probe configuration
readinessProbe: {}
# -- Startup probe configuration
startupProbe: {}
# -- Node selector for pod scheduling
nodeSelector: {}
# -- Tolerations for pod scheduling
tolerations: []
# -- Affinity rules for pod scheduling
affinity: {}
# -- Topology spread constraints
topologySpreadConstraints: []
# -- Extra environment variables
extraEnvs: []
# -- Extra volume mounts
extraVolumeMounts: []
# -- Extra volumes
extraVolumes: []
# -- Extra init containers
initContainers: []
# -- Extra sidecar containers
extraContainers: []
# -- Pod annotations
podAnnotations: {}
# -- Pod labels
podLabels: {}
# -- Extra labels for the Deployment
extraLabels: {}
# -- Update strategy
strategy:
type: RollingUpdate
# -- Priority class name
priorityClassName: ""
# -- DNS policy
dnsPolicy: ""
# -- DNS config
dnsConfig: {}
# -- DaemonSet-specific configuration (only used when kind is 'DaemonSet')
daemonset:
useHostNetwork: false # also modify dnsPolicy accordingly
useHostPort: false
hostIP: null
hostPorts:
http: 80
https: 443
stat: 1024
metrics: 31060
# -- Service configuration
service:
# -- Enable the Service
enabled: true
# -- Service type
type: NodePort
# -- Service annotations
annotations: {}
# -- Service labels
labels: {}
# -- External traffic policy
externalTrafficPolicy: ""
# -- HTTP port configuration
http:
port: 31080
targetPort: 31080
nodePort: 31080
# -- HTTPS port configuration
https:
port: 31443
targetPort: 31443
nodePort: 31443
# -- Stats port configuration
stat:
port: 31024
targetPort: 31024
nodePort: ""
# -- Extra ports to expose
extraPorts: []
# -- Controller metrics port configuration (hug_* prometheus metrics)
controller-metrics:
port: 31060
targetPort: 31060
# -- Metrics service configuration (created when serviceMonitor is enabled)
metrics:
type: ClusterIP
annotations: {}
labels: {}
# -- ServiceMonitor configuration (requires Prometheus Operator)
## ref: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md
## Note: requires Prometheus Operator to be able to work, for example:
## helm install prometheus prometheus-community/kube-prometheus-stack \
## --set prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues=false \
## --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
serviceMonitor:
# -- Enable ServiceMonitor (should not be enabled together with podMonitor)
enabled: false
# -- Extra labels for ServiceMonitor target discovery
extraLabels: {}
# -- ServiceMonitor endpoints configuration
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
# -- PodMonitor configuration (requires Prometheus Operator)
## ref: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/user-guides/getting-started.md
podMonitor:
# -- Enable PodMonitor (should not be enabled together with serviceMonitor)
enabled: false
# -- Extra labels for PodMonitor target discovery
extraLabels: {}
# -- PodMonitor endpoints configuration
endpoints:
- port: stat
path: /metrics
scheme: http
interval: 30s
- port: metrics
path: /metrics
scheme: https
interval: 30s
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
# -- HorizontalPodAutoscaler configuration
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
# -- KEDA ScaledObject configuration (mutually exclusive with autoscaling)
keda:
enabled: false
minReplicas: 2
maxReplicas: 20
pollingInterval: 30
cooldownPeriod: 300
restoreToOriginalReplicaCount: false
# fallback:
# failureThreshold: 3
# replicas: 11
scaledObject:
annotations: {}
horizontalPodAutoscalerConfig: {}
# name: ""
# behavior:
# scaleDown:
# stabilizationWindowSeconds: 300
# policies:
# - type: Pods
# value: 1
# periodSeconds: 300
triggers: []
# - type: prometheus
# metadata:
# serverAddress: http://<prometheus-host>:9090
# metricName: haproxy_process_idle_time_percent
# threshold: '50'
# query: avg(100-avg_over_time(haproxy_process_idle_time_percent{job="haproxy-unified-gateway"}[2m]))
# -- PodDisruptionBudget configuration
podDisruptionBudget:
enabled: false
# minAvailable: 1
# maxUnavailable: 1
# -- HugConf custom resource configuration
hugconf:
# -- Create a HugConf resource
create: true
# -- HugConf name
name: hugconf
# -- Logging configuration
logging:
# -- Default log level
defaultLevel: Info
# -- Per-category log level overrides
categoryLevelList:
- category: "k8s"
level: "Error"
- category: "gate"
level: "Info"
- category: "status"
level: "Info"
- category: "batch"
level: "Error"
- category: "app"
level: "Info"
- category: "certs-storage"
level: "Info"
# -- Global configuration reference (group, kind, name, namespace)
globalRef: {}
# group: gate.v3.haproxy.org
# kind: Global
# name: global
# namespace: haproxy-unified-gateway
# -- Defaults configuration reference (group, kind, name, namespace)
defaultsRef: {}
# group: gate.v3.haproxy.org
# kind: Defaults
# name: haproxytech
# namespace: haproxy-unified-gateway
# -- CRD Job configuration
crdjob:
# -- Enable the CRD installation Job (Helm hook)
enabled: true
# -- Additional pod annotations
podAnnotations: {}
# -- TTL for completed jobs (seconds)
ttlSecondsAfterFinished: 60
# -- Node selector
nodeSelector: {}
# -- Tolerations
tolerations: []
# -- Affinity
affinity: {}
# -- Resources for CRD job
resources: {}
# -- Image override (defaults to controller image)
image: {}
# -- Gateway API Job configuration
gwapijob:
# -- Enable the Gateway API CRD installation Job (Helm hook)
enabled: true
# -- Gateway API version to install
version: "1.3.0"
# -- Additional pod annotations
podAnnotations: {}
# -- TTL for completed jobs (seconds)
ttlSecondsAfterFinished: 60
# -- Node selector
nodeSelector: {}
# -- Tolerations
tolerations: []
# -- Affinity
affinity: {}
# -- Resources for Gateway API job
resources: {}
# -- Image override (defaults to controller image)
image: {}