Skip to content

Latest commit

 

History

History
254 lines (193 loc) · 12.1 KB

File metadata and controls

254 lines (193 loc) · 12.1 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

Linting and Template Validation (no cluster needed)

# Test all charts
./test/local-test.sh

# Test a single chart
./test/local-test.sh haproxy-unified-gateway
./test/local-test.sh kubernetes-ingress

# Helm lint a chart directly
helm lint kubernetes-ingress/
helm lint haproxy-unified-gateway/ -f haproxy-unified-gateway/ci/deployment-default-values.yaml

# Render templates to stdout
helm template test-release kubernetes-ingress/
helm template test-release haproxy-unified-gateway/ --set controller.kind=DaemonSet
helm template test-release haproxy-unified-gateway/ --api-versions monitoring.coreos.com/v1

Chart-testing (ct) — matches CircleCI

# Lint all charts
./test/ct-test.sh lint

# Lint a single chart
./test/ct-test.sh lint haproxy-unified-gateway

# Install (creates a Kind cluster automatically)
./test/ct-test.sh install haproxy-unified-gateway

# Keep the Kind cluster after install tests
KIND_KEEP_CLUSTER=1 ./test/ct-test.sh install

Integration Tests (real Kind cluster)

# Test all charts
./test/integration-test.sh

# Test a single chart
./test/integration-test.sh haproxy-unified-gateway

# Run a specific test scenario (defaults, daemonset, hpa, pdb, metrics-port, monitoring, hugconf-cleanup, ci)
TEST_FILTER=monitoring ./test/integration-test.sh haproxy-unified-gateway

# Keep namespaces after failure for debugging
KEEP_NS=1 ./test/integration-test.sh

Contribution Requirements

  • All commits require a Signed-off-by line (DCO): git commit -s -m "message"
  • Any change to a chart requires a chart version bump in Chart.yaml following semver
  • Submit changes to multiple charts in separate PRs

Project Structure

This repo contains Helm charts for HAProxy products:

  • kubernetes-ingress/ - HAProxy Kubernetes Ingress Controller chart (mature, feature-rich)
  • haproxy/ - HAProxy community chart
  • haproxy-unified-gateway/ - HAProxy Unified Gateway (HUG) chart

kubernetes-ingress Chart

  • Chart version: follows its own semver (currently 1.49.x)
  • Image: haproxytech/kubernetes-ingress
  • Supports: Deployment + DaemonSet modes, IngressClass, Gateway API, HPA, KEDA, ServiceMonitor/PodMonitor, PDB, proxy service (fetch sync mode), ConfigMap-based HAProxy config, publish-service, default TLS cert generation
  • Templates: 25 files in templates/
  • CI tests: 38 test value files in ci/
  • Kubernetes: >=1.23
  • Maintainer: Dinko Korunic

haproxy-unified-gateway Chart

  • Chart version: 0.1.0 (appVersion 0.9.1)
  • Image: haproxytech/haproxy-unified-gateway
  • Purpose: Kubernetes Gateway API controller powered by HAProxy
  • Kubernetes: >=1.26
  • Binary: /usr/local/sbin/hug inside the container
  • Entry point: /start.sh
  • Key flag: --hugconf-crd=<namespace>/<name> for HugConf CRD reference

Templates

Template Purpose
_helpers.tpl Name, labels, image, serviceAccount, hugconfCrd, serviceMonitorName, podMonitorName helpers
controller-deployment.yaml Deployment (when controller.kind=Deployment)
controller-daemonset.yaml DaemonSet with hostNetwork/hostPort support (when controller.kind=DaemonSet)
controller-service.yaml NodePort Service (HTTP 31080, HTTPS 31443, Stats 31024)
controller-serviceaccount.yaml ServiceAccount
clusterrole.yaml RBAC: Gateway API resources, HUG CRDs (gate.v3.haproxy.org incl. globals/defaults), core K8s resources, auth/authz for kube-rbac metrics
clusterrolebinding.yaml ClusterRoleBinding
controller-hugconf.yaml HugConf CR (logging, globalRef, defaultsRef configuration) — post-install hook (weight 5)
controller-hugconf-cleanup.yaml Pre-delete hook Job that deletes the HugConf CR on helm uninstall
controller-crdjob.yaml Helm hook Job: installs HUG CRDs (--job-check-crd) — post-install hook (weight 0)
controller-crdjob-rbac.yaml SA + ClusterRole + Binding for CRD/GWAPI jobs
controller-gwapijob.yaml Helm hook Job: installs Gateway API CRDs (--job-gwapi=VERSION)
controller-hpa.yaml HPA (disabled by default, mutually exclusive with KEDA)
controller-keda.yaml KEDA ScaledObject (disabled by default, Deployment only)
controller-servicemonitor.yaml ServiceMonitor for Prometheus Operator (disabled by default, gated behind .Capabilities.APIVersions)
controller-podmonitor.yaml PodMonitor for Prometheus Operator (disabled by default, gated behind .Capabilities.APIVersions)
controller-service-metrics.yaml ClusterIP metrics Service with stat + metrics ports (created when serviceMonitor is enabled)
controller-poddisruptionbudget.yaml PDB (disabled by default)
controller-podsecuritypolicy.yaml PSP (disabled by default, K8s <1.25 only)
controller-role.yaml Role for PSP usage
controller-rolebinding.yaml RoleBinding for PSP Role
namespace.yaml Optional namespace creation (pre-install hook)
NOTES.txt Post-install instructions

Values Structure

  • rbac.create - RBAC resources
  • namespace.create - optional namespace
  • serviceAccount - create, name, annotations
  • controller - kind (Deployment/DaemonSet), image, replicaCount, hugconfCrd, metricsAuth, extraArgs, containerPort, resources, securityContext, probes, scheduling (nodeSelector/tolerations/affinity/topologySpreadConstraints), extraEnvs/Volumes/Containers, daemonset (useHostNetwork/useHostPort/hostPorts/hostIP), service config (incl. metrics service), serviceMonitor, podMonitor, autoscaling, keda (ScaledObject), PDB
  • hugconf - create, name, logging (defaultLevel, categoryLevelList), globalRef, defaultsRef
  • crdjob - enabled, podAnnotations, ttl, scheduling, resources, image override
  • gwapijob - enabled, version (Gateway API CRD version), same options as crdjob

Metrics

HUG exposes two separate metrics endpoints:

Port Name Source Default
31024 stat HAProxy stats (via --stats-port) Always exposed
31060 metrics Controller metrics (via --controller-port) Always exposed
  • controller.metricsAuth controls --metrics-auth flag; default is kube-rbac
  • Supported values: none, kube-rbac, basic
  • When kube-rbac: controller serves HTTPS, validates bearer tokens via TokenReview API
  • When none: plain HTTP, no authentication
  • ClusterRole includes tokenreviews and subjectaccessreviews for kube-rbac auth
  • The metrics Service (controller-service-metrics.yaml) exposes both stat and metrics ports, created only when ServiceMonitor is enabled

What HUG chart intentionally does NOT have (compared to kubernetes-ingress)

  • No IngressClass
  • No ConfigMap-based HAProxy configuration
  • No proxy service / fetch sync mode
  • No publish-service
  • No default TLS cert generation

HUG Source Project

Source code lives at: /home/zlatko/src/gitlab.int.haproxy.com/zbratkovic/unified-k8s-gateway

Key paths in source:

  • cmd/controller/main.go - controller entry point
  • hug/configuration/configuration.go - CLI flags definition
  • build/Dockerfile - container image build
  • api/definition/ - CRD definitions
  • example/dev-init/ - example Gateway/HTTPRoute manifests
  • documentation/metrics*.md - metrics documentation

HUG Controller Flags

All flags (for extraArgs):

Flag Default Description
--hugconf-crd namespace/name of the HugConf CRD
--controller-name gate.haproxy.org/hug spec.controllerName GatewayClass selector
--ipv4-bind-address IPv4 address to bind to
--ipv6-bind-address IPv6 address to bind to
--log-type json Log output type (text or json)
--job-gwapi Install Gateway API experimental CRDs for given version (e.g. 1.3.0) and exit
--namespaces Comma-separated list of namespaces to monitor
--stats-port 1024 Port for HAProxy stats
--controller-port 31060 Port for controller metrics (prometheus)
--sync-period 0 Period for HAProxy config computation (e.g. 5s, 1m)
--startup-sync-period 0 Startup period for HAProxy config computation
--cache-resync-period 0 Controller-runtime manager cache SyncPeriod (default: 10 hours)
--add-stats-port true Add stats port bind to existing stats frontend
--force-restart-haproxy false Force HAProxy restart at controller startup
--leader-election-enabled false Enable leader election
--with-s6-overlay false Use s6 overlay to start/stop/restart HAProxy
--with-pebble false Use pebble to start/stop/restart HAProxy
--disable-ipv4 false Disable IPv4 support
--disable-ipv6 false Disable IPv6 support
--job-check-crd false Run CRD refresh job and exit
-e / --external false Use as external controller (out of k8s cluster)
--external-config-dir Path to HAProxy configuration directory
--external-haproxy-binary Path to HAProxy binary
--external-runtime-dir Path to HAProxy runtime directory
--external-state-dir Path to HAProxy state directory
--external-aux-dir Path to HAProxy aux directory
--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)
-t false Simulate running HAProxy (test mode)

Note: The HUG binary default for --metrics-auth is none, but the Helm chart overrides this to kube-rbac via controller.metricsAuth.

CI Values Files

23 test value files in haproxy-unified-gateway/ci/:

  • 8 DaemonSet variants (default, customnodeport, extraargs, extraenvs, extraports, hostport, serviceannotation, strategy)
  • 15 Deployment variants (default, customnodeport, disabled-jobs, extraargs, extraenvs, extraports, hpa, hugconf, keda, keda-advanced, metrics-none, pdb, podmonitor, servicemonitor, strategy)

Naming convention: <mode>-<feature>-values.yaml

Testing

Three test scripts in test/:

Script Purpose
test/local-test.sh Offline lint + template validation (no cluster needed)
test/integration-test.sh Deploy to a real Kind cluster and verify resources
test/ct-test.sh Wrapper around ct (chart-testing), matches CircleCI pipeline

local-test.sh

Tests: Chart.yaml metadata, helm lint, helm template, Deployment vs DaemonSet switching, HugConf cleanup hooks, metrics port rendering + --metrics-auth flag, ServiceMonitor/PodMonitor rendering, all ci/ values files.

integration-test.sh

Tests on a real Kind cluster: default install, DaemonSet mode, HPA, PDB, metrics port (container port 31060, --metrics-auth=kube-rbac arg), ServiceMonitor/PodMonitor with metrics Service port verification, HugConf cleanup on uninstall, all ci/ values files.

TEST_FILTER values: defaults, daemonset, hpa, pdb, metrics-port, monitoring, hugconf-cleanup, ci

ct-test.sh

Runs ct lint and ct install locally, same as CircleCI. Auto-downloads chart_schema.yaml and lintconf.yaml from the ct release on first run (files are gitignored).

Modes: lint, install, all

CircleCI Pipeline

.circleci/config.yml workflow: lint-scripts (shellcheck) -> lint-charts (ct lint) -> install-charts (ct install on Kind) -> release-charts (helm package + push to GitHub Releases, GHCR OCI, update gh-pages index).

Conventions

  • Template names prefixed with controller- for controller-specific resources
  • All templates use include "<chart>.fullname" for resource naming
  • All templates use include "<chart>.namespace" for namespace
  • Helm hooks used for CRD installation jobs (post-install, pre-upgrade)
  • ArgoCD hook annotations included alongside Helm hooks
  • HugConf CR is a post-install hook (weight 5) that runs after the CRD job (weight 0)
  • HugConf cleanup is a pre-delete hook Job
  • Security context: non-root (UID 1000), CAP_NET_BIND_SERVICE, seccomp RuntimeDefault
  • ServiceMonitor/PodMonitor gated behind .Capabilities.APIVersions "monitoring.coreos.com/v1"