Unreleased documentation. Choose your installed release in the version menu. Features described here may be absent from that release.
Upgrade notes¶
Check the notes for every version between your installed version and the version you plan to deploy. Each section lists configuration changes and the steps needed to keep your existing routes working. For routine chart upgrades, see Upgrading with Helm.
Upgrading to 0.5¶
0.5 lets a new HAProxy pod load a previously acknowledged configuration when a restarted controller or new leader can't render. During recovery, existing configured pods keep serving without a reload. Follow the normal Helm upgrade procedure; this feature needs no new Helm values.
Establish a recovery checkpoint¶
Before relying on retained recovery during node maintenance, let a 0.5 controller complete a successful configuration deployment and publish its acknowledgement. That creates the retained configuration and auxiliary files in Kubernetes. An installation upgraded while rendering is already blocked has no checkpoint from the older controller. Repair the rendering error first; upgrading alone doesn't make replacement HAProxy pods Ready in that case.
The controller uses a checkpoint only when it matches the latest recorded deployment and the configured HAProxy pods. A newer deployment without a usable checkpoint prevents recovery from an older one. Retained recovery also requires at least one controller to pass its startup checks.
Account for frozen routing inputs¶
While rendering is blocked, replacement pods receive the retained endpoint lists, routes, certificates, and fetched files. They don't receive subsequent input changes until rendering recovers. A Ready proxy can therefore still point at a backend address that no longer exists.
The bundled PrometheusRule alerts when retained recovery is active. /healthz
includes the render error but continues to report controller component health;
HTTP 200 doesn't prove that current routing inputs have been applied. See
controller failure behavior
for recovery checks and monitoring.
Upgrading to 0.4¶
0.4 ships a values schema. Helm checks your values against it on every
helm install, helm upgrade, helm template, and helm lint, and refuses the
release if a key is unknown or a value has the wrong type. Earlier versions
ignored such keys, so a values file that installs 0.3 can fail on 0.4. If you run
0.2, complete Upgrading to 0.3 first.
Confirm that the target version is available on the releases page before running the upgrade commands.
1. Save your values¶
Set the installed Helm release and namespace:
Export the values you supplied to Helm:
umask 077
helm get values "$HAPTIC_RELEASE" --namespace "$HAPTIC_NAMESPACE" \
--output yaml > haptic-values-0.4.yaml
if [ "$(cat haptic-values-0.4.yaml)" = null ]; then
printf '{}\n' > haptic-values-0.4.yaml
fi
If you manage values in Git, check that file instead, and apply the fixes from the next step to it.
2. Check your values against the schema¶
Render the 0.4 chart with your values. This contacts no cluster and changes nothing:
helm template "$HAPTIC_RELEASE" \
oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--version 0.4.1 --namespace "$HAPTIC_NAMESPACE" \
--values haptic-values-0.4.yaml > /dev/null
The command prints nothing when your values pass. Otherwise Helm names each rejected value by its path:
Error: values don't meet the specifications of the schema(s) in the following chart(s):
haptic:
- at '/controller/service': additional properties 'tpye' not allowed
- at '/haproxy/ports/http': got string, want integer
Fix each reported value, then run the command again until it passes:
- Unknown key: correct the spelling, or delete the key. A key the chart moved or renamed fails with a message that names its replacement.
- Wrong type: remove the quotes from a number or a boolean, for example
"8080"→8080and"true"→true.
Free-form maps keep accepting any key: labels, annotations, selectors,
resources, security contexts, affinity, and the top level of
controller.config.templatingSettings.extraContext.
3. Check auth-headers-request header names¶
haproxy-haptic.org/auth-headers-request and
haproxy-ingress.github.io/auth-headers-request no longer forward header names
that contain _. List them; this needs kubectl and jq:
kubectl get ingress --all-namespaces --output json |
jq -r '.items[] | .metadata as $m | ($m.annotations // {}) | to_entries[]
| select(.key == "haproxy-haptic.org/auth-headers-request"
or .key == "haproxy-ingress.github.io/auth-headers-request")
| select(.value | contains("_"))
| "\($m.namespace)/\($m.name) \(.key): \(.value)"'
Replace _ with - in each listed header name, and have clients send the
dashed header. The auth service needs no change: HAPTIC already delivered these
headers to it with - in their names.
If you don't: the header isn't forwarded to the auth service, the Ingress
gets an InvalidAuthHeader Warning Event, and the admission webhook denies new
or changed Ingresses that list one.
4. Review Gateway route timeouts¶
HAPTIC now ignores rules[].timeouts.request and uses only backendRequest for
HAProxy's server inactivity timeout, matching HAProxy Unified Gateway's field
mapping. Previously, request took precedence over backendRequest.
If you used request: 30s to set the server timeout, move that value to
backendRequest in the route rule:
If both fields are set, the existing backendRequest value now applies. If
backendRequest is absent, the backend default applies. A zero backendRequest
now uses HAProxy's maximum timeout (about 24.9 days) instead of the backend
default.
These settings limit inactivity. HAPTIC doesn't enforce an overall request deadline across retries; see Timeout limits.
5. Monitor rejected resource changes¶
Alert when haptic_rejected_watched_inputs is greater than zero. HAPTIC now keeps
an invalid resource change out of otherwise valid updates, so healthy traffic
doesn't prove every intended change took effect. A rejected credential rotation
or policy update retains the previous validated behavior. See
Rejected resource changes for diagnosis and
restart behavior.
6. Upgrade the release¶
Pass the checked values file. --reset-values starts from the new chart's
defaults, so the release doesn't carry rejected keys forward:
helm upgrade "$HAPTIC_RELEASE" \
oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--namespace "$HAPTIC_NAMESPACE" --version 0.4.1 \
--reset-values \
--values haptic-values-0.4.yaml
Upgrading to 0.3¶
Use this checklist to upgrade a 0.2 release. Work through it from top to bottom; each step says what to change, and what fails if you don't. If you run 0.1.0 or a 0.2.0 alpha, complete Upgrading to 0.2 first.
Confirm that the target version is available on the releases page before running the upgrade commands. Development documentation can describe a release before its artifacts are published.
1. Save your values¶
Set the installed Helm release and namespace:
Export the values you supplied to Helm, and copy them into a working file for the upgrade:
umask 077
helm get values "$HAPTIC_RELEASE" --namespace "$HAPTIC_NAMESPACE" \
--output yaml > haptic-values-before.yaml
cp haptic-values-before.yaml haptic-values-0.3.yaml
If the export contains only null, replace it with an empty map:
Apply the following steps to haptic-values-0.3.yaml. If you manage values in
Git, apply them to that source too.
2. Rename the timeout and SSL redirect keys¶
Under controller.config.templatingSettings.extraContext, rename these keys:
| 0.2 key | 0.3 key |
|---|---|
timeout_connect |
timeoutConnect |
timeout_client |
timeoutClient |
timeout_server |
timeoutServer |
timeout_http_request |
timeoutHttpRequest |
timeout_http_keep_alive |
timeoutHttpKeepAlive |
ssl_redirect_default |
sslRedirectDefault |
sslRedirectDefault is a boolean. Write true, not "true":
controller:
config:
templatingSettings:
extraContext:
timeoutConnect: "5000"
sslRedirectDefault: true
If you don't: Helm refuses to install or upgrade the chart, for example:
controller.config.templatingSettings.extraContext.timeout_connect was renamed in 0.3.0 and no longer has any effect. Rename it to timeoutConnect.
A quoted sslRedirectDefault: "true" fails the same way, because a string
would never turn the redirect on.
3. Move the HSTS max-age¶
extraContext.hapticHstsMaxAge is removed. haproxy-haptic.org/hsts without
haproxy-haptic.org/hsts-max-age now sends max-age from tls.hsts.maxAge,
which defaults to one year (31536000) instead of two.
If you set hapticHstsMaxAge, or you want to keep the two-year default, set
tls.hsts.maxAge:
tls.hsts.maxAge also sets the max-age of the global HSTS header when
tls.hsts.enabled is true.
If you don't: a leftover hapticHstsMaxAge fails the install with the same
"was renamed in 0.3.0" error as step 2. Without it, Ingresses using
haproxy-haptic.org/hsts send max-age=31536000.
4. Replace basic-auth hashes HAPTIC now refuses¶
Every auth-secret annotation (haproxy-haptic.org, haproxy.org,
haproxy-ingress.github.io, and nginx.ingress.kubernetes.io) accepts only
bcrypt, SHA-256 crypt, SHA-512 crypt, and yescrypt hashes by default. It
refuses $apr1$ (Apache MD5), {SHA}, $1$ (MD5-crypt),
Data Encryption Standard (DES) crypt, and plaintext credentials.
Preflight validation doesn't read your cluster's Secrets, so check them before
upgrading. This lists every user whose hash the 0.3 default refuses; it needs
kubectl and jq:
pattern='^\$(2[aby]|5|6|y)\$[./0-9A-Za-z$=]+$'
kubectl get ingress --all-namespaces --output json |
jq -r '.items[] | .metadata as $m | ($m.annotations // {}) | to_entries[]
| select(.key | endswith("/auth-secret"))
| (if (.value | contains("/")) then .value else "\($m.namespace)/\(.value)" end)
+ " " + $m.namespace + "/" + $m.name' |
sort -u |
while read -r secret ingress; do
kubectl get secret --namespace "${secret%%/*}" "${secret#*/}" --output json |
jq -r --arg secret "$secret" --arg ingress "$ingress" --arg pattern "$pattern" '
.data
| if has("auth") then
.auth | @base64d | split("\n")[] | rtrimstr("\r")
| select(contains(":")) | capture("^(?<user>[^:]*):(?<hash>.*)$")
else
to_entries[] | {user: .key, hash: (.value | @base64d)}
end
| select(.hash | test($pattern) | not)
| "Ingress \($ingress): Secret \($secret), user \(.user)"'
done
For each user listed, generate a new hash and write it into the Secret in the format the Secret already uses. Each command prompts for the password:
| Format | Command |
|---|---|
| bcrypt | htpasswd -nB <user> |
| SHA-512 crypt | openssl passwd -6 |
| SHA-256 crypt | openssl passwd -5 |
| yescrypt | mkpasswd -m yescrypt |
If you don't: rendering fails with an error that names the Ingress, the Secret, and the user. The admission webhook denies new or changed Ingresses that reference such a Secret, and while one is in the cluster, HAPTIC applies no configuration changes. To keep accepting a format while you migrate, widen the patterns as shown in Basic-auth password hashes.
5. Check host alias annotations¶
haproxy-haptic.org/host-alias-regex and haproxy-ingress.github.io/server-alias-regex
must now match the whole hostname; in 0.2 they matched any part of it. List every
regex alias; this needs kubectl and jq:
kubectl get ingress --all-namespaces --output json |
jq -r '.items[] | .metadata as $m | ($m.annotations // {}) | to_entries[]
| select(.key == "haproxy-haptic.org/host-alias-regex"
or .key == "haproxy-ingress.github.io/server-alias-regex")
| "\($m.namespace)/\($m.name) \(.key): \(.value)"'
For each regex that should match only part of a hostname, widen it to cover the
rest. For example, example\.com becomes .*example\.com, and example becomes
.*example.*. A regex that already starts with ^ and ends with $ needs no
change. HAPTIC also rejects a regex whose groups or [ ] classes don't close
within it.
Exact aliases (haproxy-haptic.org/host-alias, haproxy-ingress.github.io/server-alias,
and nginx.ingress.kubernetes.io/server-alias) must now be valid hostnames,
optionally starting with *.; case doesn't matter. List the aliases HAPTIC now
refuses:
kubectl get ingress --all-namespaces --output json |
jq -r '.items[] | .metadata as $m | ($m.annotations // {}) | to_entries[]
| select(.key == "haproxy-haptic.org/host-alias"
or .key == "haproxy-ingress.github.io/server-alias"
or .key == "nginx.ingress.kubernetes.io/server-alias")
| .key as $key
| .value | split(if $key == "haproxy-haptic.org/host-alias" then "[, ]" else "," end; null)[]
| gsub("^\\s+|\\s+$"; "") | select(. != "")
| select(test("^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"; "i") | not)
| "\($m.namespace)/\($m.name) \($key): \(.)"'
Remove or correct each listed alias. A port, a path, or an underscore can't be part of an alias.
If you don't: a regex that relied on matching part of a hostname stops
matching, and requests for those hostnames no longer reach the Ingress. An
invalid alias or regex is skipped with an InvalidHostAlias,
InvalidServerAlias, InvalidServerAliasRegex, InvalidHostAliasRegex or
InvalidAnnotationValue Warning Event, and the admission webhook denies new or
changed Ingresses that carry one.
6. Update custom templates¶
If your values add templates, snippets, or libraries, make these changes:
| 0.2 | 0.3 |
|---|---|
http.Fetch option delay |
interval |
strings_replace(s, old, new) |
replace(s, old, new) |
trim(s) to strip whitespace |
strip(s) |
trim is now the trim(s, cutset) builtin in every render path. To find
candidates in your values file:
If you don't: the configuration fails to load, and preflight
reports the error. An http.Fetch call that sets delay fails with
option "delay" was removed, so this call fails. Rename it to "interval".
7. Update custom validation tests¶
Assertions in validationTests no longer see your templatingSettings.extraContext.
They render with the libraries' defaults, testExtraContext (which the chart
sets from its default values), _global's extraContext, and the test's own
extraContext. A test that asserts output of a value you set must set that
value itself:
controller:
config:
validationTests:
test-my-timeouts:
extraContext:
timeoutConnect: "5000"
# fixtures and assertions unchanged
Each test also renders its fixtures a second time with your extraContext.
That render must succeed and, where the test asserts haproxy_valid, pass
haproxy -c. See Extra context.
If you don't: a test asserting one of your values fails, and so does a
test whose fixtures your values break. Either failure stops the configuration
from loading, and preflight reports it, for example
This test's fixtures fail to render with the deployment's extraContext.
8. Prepare for HTTP/3¶
0.3 enables HTTP/3 by default. Every
TLS-terminating HTTPS listener also listens on UDP, and HTTPS responses
advertise it with an alt-svc header. The HAProxy Service gains a UDP port
named https-quic with the https port's number and nodePort, and each
Gateway's Service gains a UDP port for each TLS-terminating HTTPS listener. The chart's
NetworkPolicy allows it.
Before upgrading, choose one:
- Allow UDP on the HTTPS port (443 by default), or on its nodePort, through
firewalls, security groups, and load balancers in front of HAProxy. A
LoadBalancerService now mixes TCP and UDP ports, so check that your load-balancer implementation supports that. -
Keep HAProxy TCP-only:
If your load balancer publishes UDP on a different port than TCP, set
http3.altSvc.port; see HTTP/3 (QUIC).
If you don't: where UDP is blocked, clients fall back to HTTP/2 or
HTTP/1.1 over TCP after trying QUIC. An entry named https-quic in
haproxy.service.extraPorts fails the install; rename it or turn HTTP/3 off.
9. Check deployment-specific settings¶
Skip each item that doesn't apply to you.
Varnish cache (cache.varnish.enabled: true). Varnish runs as a bundled
non-root image that needs the IPC_LOCK capability. Kubernetes Baseline and
Restricted Pod Security Standards reject it, so arrange a policy exception with
your cluster administrator before upgrading. If you set cache.varnish.image,
remove the override to use the bundled image, or supply an image with
cap_ipc_lock=ep on varnishd. If you don't: your cluster's policy rejects
the Varnish pods. See shared-log memory.
Controller probe overrides. The chart probes controller readiness on
/readyz and liveness on /livez. If your values set
controller.readinessProbe.httpGet.path or controller.livenessProbe.httpGet.path,
change them:
If you don't: probes on /healthz mark the leading replica unready and
restart it while a new configuration fails to load, so admission requests are
denied.
Your own controller NetworkPolicy. If you replace the chart's
NetworkPolicy, allow controller pods to reach each other on the health port
(controller.ports.healthz, default 8080).
Monitoring. haptic_events_dropped_total is removed. Query
haptic_events_dropped_critical_total, which counted the same drops.
Custom agent clients. If your own code calls the agent's /v1/apply, set
identity_version: 1 in the manifest. If you don't: the agent rejects the
manifest with 400. HAPTIC's own controller already sets it.
10. Validate the candidate¶
Use the haptic binary matching the chart version to run
preflight validation:
helm pull oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--version 0.3.0 --untar --untardir ./haptic-0.3-chart
haptic preflight --values ./haptic-values-0.3.yaml \
--chart ./haptic-0.3-chart/haptic --expect-chart-version 0.3.0 \
--namespace "$HAPTIC_NAMESPACE" --release "$HAPTIC_RELEASE"
Fix every reported error and run it again until it passes.
0.3 adds the testExtraContext field to the HAProxyTemplateConfig and
HAProxyTemplateLibrary CRDs. Keep the chart's CRD upgrade hook enabled. If you
manage CRDs separately, apply the target chart's schemas before upgrading:
helm show crds oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--version 0.3.0 | kubectl apply --server-side --force-conflicts -f -
11. Upgrade the release¶
Pass the complete migrated values file. --reset-values starts from the new
chart's defaults, so removed keys aren't carried forward from the installed
release:
helm upgrade "$HAPTIC_RELEASE" \
oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--namespace "$HAPTIC_NAMESPACE" --version 0.3.0 \
--reset-values \
--values haptic-values-0.3.yaml
If validation rejects the candidate, fix the reported value or template and repeat the upgrade. For rollout failures, see Recover a failed upgrade.
12. Verify the deployment¶
Wait for the controller and HAProxy deployments:
kubectl --namespace "$HAPTIC_NAMESPACE" get deployments \
--selector "app.kubernetes.io/instance=$HAPTIC_RELEASE" --output name | \
while read -r deployment; do
kubectl --namespace "$HAPTIC_NAMESPACE" rollout status "$deployment" --timeout=7m
done
The HAProxyTemplateConfig should report Validated=True; check any False
condition on HAProxyCfg:
Test existing HTTP and HTTPS routes, including authentication and custom annotations.
Behavior changes to review¶
These need no action unless you depend on the old behavior:
- Response headers on generated responses. The chart sets
Server, HSTS, Ingress custom response headers, and routing diagnostic headers withhttp-after-response, so error pages, denials, and redirects that HAProxy generates or replaces carry them too. A snippet that changes one of these headers withhttp-responseruns before the chart's rule; usehttp-after-responseinstead. - HSTS default.
haproxy-haptic.org/hstswithouthsts-max-agesends one year instead of two; see step 3. - nginx-ingress regex paths. With
use-regexorrewrite-target, a path containing regex syntax matches as a case-insensitive regex anchored at the path's start, and$Ninrewrite-targetrefers to its capture groups. In 0.2 the path matched as a literal prefix. Seeuse-regex. - Host alias conflicts. An exact alias for a hostname that an older Ingress
already claims, as a rule host or alias, is no longer routed, and the newer Ingress
gets a
RouteConflictWarning Event. See Host aliases claim hostnames. - A failing configuration change. While a new configuration fails to load,
the leading controller replica keeps serving and validating the previous one,
so admission keeps working. Other replicas report unready and restart.
/healthzstill reports the failure. See health checks.
Upgrading to 0.2¶
Use this guide to upgrade from 0.1.0 or a 0.2.0 alpha to a stable 0.2 release. The controller and chart share one version. The chart replaces the HAProxy Data Plane API with the HAPTIC agent and changes several values paths.
Confirm that the target version is available on the releases page before running the upgrade commands. Development documentation can describe a release before its artifacts are published.
Check requirements¶
- Kubernetes 1.33 or newer. The HAProxy pod uses native sidecars to keep its agent, Stream Processing Offload Agent (SPOA) hub, and log collector running until HAProxy exits.
- Capacity for the whole installation and its rolling upgrade. The defaults request about 5.4 GiB of memory, rising to 8.1 GiB during rollout. The pre-rollout validation Job has a separate 1 GiB limit. Use the resource sizing guidance for larger installations or customized pod resources.
- Access to the controller registry from HAProxy pods: their agent now uses the HAPTIC image. Set image-pull credentials if your cluster requires them.
The chart supports HAProxy 3.0–3.4. Keep your selected haproxyVersion unless
you intend to change it; the default is 3.4. See
HAProxy versions for runtime-update coverage.
Save your values¶
Set the installed Helm release and namespace, and the 0.2 release to upgrade to:
Export the values you supplied to Helm:
umask 077
helm get values "$HAPTIC_RELEASE" --namespace "$HAPTIC_NAMESPACE" \
--output yaml > haptic-values-before.yaml
Copy the exported values, which include settings supplied with --set, into a
working file for the upgrade:
If the export contains only null, replace it with an empty map:
Keep haptic-values-before.yaml as the record of your previous configuration.
If you manage values in Git, also apply the migrations below to that source so
subsequent deployments keep them.
Migrate 0.1.0 values¶
For an alpha installation, some migrations may already be applied. Check the values you use against the table and review the changed defaults before validation.
For 0.1.0, update the paths you use in haptic-values-0.2.yaml:
| Previous value | Replacement |
|---|---|
Root controller workload settings, such as image, replicaCount, resources, webhook, monitoring, networkPolicy, probes, and autoscaling |
The same setting under controller.* |
Root pod settings, such as imagePullSecrets, nodeSelector, tolerations, affinity, podAnnotations, and podSecurityContext |
The same setting under controller.podSpec.* |
HAProxy pod settings, such as haproxy.nodeSelector, .tolerations, .affinity, .podAnnotations, and .podSecurityContext |
The same setting under haproxy.podSpec.* |
controller.crdName |
controller.configName |
controller.debugPort |
controller.ports.healthz |
controller.defaultSSLCertificate |
defaultSSLCertificate |
controller.config.dataplane.port |
haproxy.ports.dataplane |
controller.config.routing.regexMatchOrder |
controller.config.templatingSettings.extraContext.routing.regexMatchOrder |
controller.templateLibraries.pathRegexLast.enabled: true |
controller.config.templatingSettings.extraContext.routing.regexMatchOrder: last |
haproxy.dataplane.logLevel, .resources, .extraEnv, and .service |
The same setting under haproxy.agent.* |
For example, controller replicas and a custom default certificate now use:
controller:
replicaCount: 2
defaultSSLCertificate:
secretName: my-default-certificate
certManager:
enabled: false
Remove Data Plane API-only values (haproxy.dataplane.validateConfig,
debugSocketPath, aclFormat, and haproxy.dataplaneBin),
haproxy.enterprise.version, and
controller.config.templatingSettings.extraContext.serverSlots.
haproxyVersion selects the Enterprise revision when Enterprise is enabled.
Remove spoaHub.plugins.otel. Configure tracing through
the tracing values instead.
The chart rejects legacy paths with their replacements. Run the validation step
below to find remaining paths, including renamed extraContext settings.
Review changed defaults and integrations¶
The default IngressClass and GatewayClass names change from haproxy to
haptic. To preserve routes that use the 0.1.0 defaults, add these values:
Keep your existing class names if you already customized them. Alternatively,
update the class references on your Ingress and Gateway resources to haptic.
Enable each vendor annotation library that your existing routes use. For example, to retain support for ingress-nginx annotations:
Use haproxyIngress.enabled for haproxy-ingress.github.io/* and
haproxytech.enabled for haproxy.org/* under the same templateLibraries map.
The native haproxy-haptic.org/* library remains enabled by default.
Review these behavior changes before upgrading:
- Access logs use JSON. Adapt custom log parsers or override the log-format snippets; see access logging.
- Ingress serves HTTPS using the default certificate. Set
controller.config.templatingSettings.extraContext.ingressDefaultHTTPS: falseif you require plaintext-only Ingress without an explicit TLS declaration. - HAProxy response compression is opt-in. If you used an alpha version's automatic
compression, set
haproxy-haptic.org/compress-enable: "true"on appropriate routes. Avoid compressing responses that combine secrets with attacker-controlled input; see compression settings. - Hash-based balancing uses consistent hashing. Existing key distribution can change during the upgrade.
- Request retries that replay a request apply to idempotent methods by default. Review custom retry settings before restoring retries for other methods.
- The backend connection timeout defaults to 100 ms instead of 5 s. For slower
networks, set
controller.config.templatingSettings.extraContext.timeout_connectto"5000"to retain the previous timeout in milliseconds. - HAProxy's HTTP/HTTPS container ports default to 80/443 instead of 8080/8443.
Update integrations that address pod ports directly, or retain the previous
ports through
haproxy.ports.httpandhaproxy.ports.https.
The webhook uses a chart-managed self-signed certificate by default. To retain
cert-manager renewal, set controller.webhook.certManager.enabled: true and
keep cert-manager installed. The chart uses a new default webhook Secret name
to avoid conflicting with the old cert-manager-owned Secret.
Update integrations that invoke haptic-controller to invoke haptic. Replace
Data Plane API integrations with the agent interface
and update dashboards using the metric migration table.
If you maintain custom templates, replace reads of parsed currentConfig
sections with currentConfig.ServerIndex for previous servers, and use
currentServers in validation fixtures. Use toJSON instead of implicit string
conversion for maps and slices. Pass the watched resource object to
statusPatch(resource, variants) instead of
separate namespace, name, API version, and kind arguments.
If you process rendered manifests, accept one HAProxyTemplateConfig and its
referenced HAProxyTemplateLibrary objects. haptic config view --input merges
them for inspection. Helm owns these objects; put persistent overrides in your
values file.
Validate the candidate¶
Use the haptic binary matching the chart version below to run
preflight validation:
helm pull oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--version "$HAPTIC_VERSION" --untar --untardir ./haptic-0.2-chart
haptic preflight --values ./haptic-values-0.2.yaml \
--chart ./haptic-0.2-chart/haptic --expect-chart-version "$HAPTIC_VERSION" \
--namespace "$HAPTIC_NAMESPACE" --release "$HAPTIC_RELEASE"
Keep the default CRD upgrade and pre-rollout validation hooks enabled. If your deployment manages CRDs separately, apply the target chart's schemas before upgrading:
helm show crds oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--version "$HAPTIC_VERSION" | kubectl apply --server-side --force-conflicts -f -
GitOps diff tools can need these CRDs before they can map the new library resources, because diff runs before Helm's hooks.
Upgrade the release¶
Pass the complete migrated values file. --reset-values starts from the new
chart's defaults before applying that file, so removed legacy settings aren't
carried forward from the installed release:
helm upgrade "$HAPTIC_RELEASE" \
oci://registry.gitlab.com/haproxy-haptic/haptic/charts/haptic \
--namespace "$HAPTIC_NAMESPACE" --version "$HAPTIC_VERSION" \
--reset-values \
--values haptic-values-0.2.yaml
If validation rejects the candidate, fix the reported value or template and repeat the upgrade. Keep validation enabled. For rollout failures and rollback limitations, see Recover a failed upgrade.
Verify the deployment¶
Wait for both controller and HAProxy deployments:
kubectl --namespace "$HAPTIC_NAMESPACE" get deployments \
--selector "app.kubernetes.io/instance=$HAPTIC_RELEASE" --output name | \
while read -r deployment; do
kubectl --namespace "$HAPTIC_NAMESPACE" rollout status "$deployment" --timeout=7m
done
Inspect configuration validation and per-pod deployment status. The
HAProxyTemplateConfig should report Validated=True; check any False
condition on HAProxyCfg for a rejected configuration or failed deployment:
Test existing HTTP and HTTPS routes, including authentication and custom annotations. A successful Helm command alone doesn't prove traffic has converged. See troubleshooting if a pod or route remains unavailable.