Description
We are seeing inconsistent live backend state between HAProxy Kubernetes Ingress replicas after redeploying an application behind a Service.
The generated haproxy.cfg on disk is updated correctly on all ingress pods after the redeploy, but the running HAProxy backend state is not updated on all pods. Some ingress replicas keep stale backend pod IPs in the live runtime state, mark them L4TOUT, and return 503. Other ingress replicas have the correct backend list and work normally.
As a workaround, adding:
haproxy.org/standalone-backend: "true"
to the Ingress makes the live backend update correctly after redeploy, and the problem disappears in our testing.
Environment
haproxytech/kubernetes-ingress chart version: 1.49.0
- AKS 1.34.2
- Argo CD
HAProxy Kubernetes Ingress values
destNamespace: haproxy-ingress
appName: haproxy-ingress
haproxy-ingress:
controller:
ingressClassResource:
name: haproxy-ingress
ingressClass: haproxy-ingress
replicaCount: 4
service:
type: LoadBalancer
externalTrafficPolicy: Local
annotations:
service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path: /healthz
service.beta.kubernetes.io/azure-load-balancer-resource-group: redacted
service.beta.kubernetes.io/azure-load-balancer-ipv4: redacted
serviceMonitor:
enabled: true
config:
cr-defaults: haproxy-ingress/haproxy-defaults
cr-frontend-http: haproxy-ingress/haproxy-frontend-http
cr-frontend-https: haproxy-ingress/haproxy-frontend-https
global-config-snippet: |
ssl-default-bind-options ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.3 no-tls-tickets
ssl-default-bind-ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384
ssl-default-bind-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
syslog-server: "address:stdout, length:8192, format:raw, facility:daemon"
extraArgs:
- --default-backend-service=x/xxx
- --disable-quic
---
apiVersion: ingress.v3.haproxy.org/v3
kind: Defaults
metadata:
name: haproxy-defaults
namespace: haproxy-ingress
spec:
compression:
direction: response
minsize_res: 500
algorithms:
- gzip
types:
- text/plain
- text/css
- application/json
- application/javascript
- application/xml
- text/xml
- text/html
redispatch:
enabled: enabled
interval: 1
retries: 3
---
apiVersion: ingress.v3.haproxy.org/v3
kind: Frontend
metadata:
name: haproxy-frontend-https
namespace: haproxy-ingress
spec:
name: haproxy-frontend-https
http_response_rule_list:
- type: del-header
hdr_name: server
- type: set-header
hdr_name: Strict-Transport-Security
hdr_format: max-age=31536000;\ includeSubDomains;\ preload;
http_request_rule_list:
- type: del-header
hdr_name: X-Forwarded-For
- type: set-header
hdr_name: X-Forwarded-Host
hdr_format: "%[req.hdr(Host)]"
- type: set-header
hdr_name: X-Forwarded-Proto
hdr_format: https
- type: set-header
hdr_name: X-Forwarded-Port
hdr_format: "443"
---
apiVersion: ingress.v3.haproxy.org/v3
kind: Frontend
metadata:
name: haproxy-frontend-http
namespace: haproxy-ingress
spec:
name: haproxy-frontend-http
http_request_rule_list:
- type: redirect
redir_type: scheme
redir_value: https
redir_code: 301
cond: unless
cond_test: "{ ssl_fc }"
Observed problem
During or after redeploy of an application behind a Service, some HAProxy ingress replicas continue to use stale backend pod IPs in the live backend state.
Symptoms:
- some ingress IPs return 503
- other ingress IPs still work
- another ingress, ingress-nginx, exposing the same app on another IP continues to work
- stats show L4TOUT on stale backend entries on affected HAProxy replicas
We initially saw this as intermittent 503 during redeploys of multiple simultaneous deployments and sometimes after pod termination events.
Evidence that generated config is correct, but runtime state is wrong
Runtime/stats output differs between HAProxy replicas
From the stats endpoint on each HAProxy ingress pod for backend zz_svc_yy-vvv_http:
haproxy-ingress-7cc59c8d86-kkj78
SRV_1 10.244.7.22:8080 L4OK
SRV_2 10.244.1.8:8080 L4OK
SRV_3 10.244.7.23:8080 L4OK
haproxy-ingress-7cc59c8d86-vhqgk
SRV_2 10.244.1.8:8080 L4OK
SRV_3 10.244.7.23:8080 L4OK
haproxy-ingress-7cc59c8d86-bfsl5
SRV_2 10.244.7.22:8080 L4OK
SRV_3 10.244.0.36:8080 L4OUT
SRV_4 10.244.2.113:8080 L4OUT
haproxy-ingress-7cc59c8d86-pvb7p
SRV_2 10.244.2.114:8080 L4OUT
SRV_3 10.244.0.36:8080 L4OUT
SRV_4 10.244.2.113:8080 L4OUT
These are not aligned across replicas, even though they are the same backend.
On-disk config is aligned across replicas
On-disk haproxy.cfg on the same pods:
haproxy-ingress-7cc59c8d86-kkj78
backend zz_svc_yy-vvv_http from haproxytech
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check
server SRV_1 10.244.7.22:8080 enabled
server SRV_2 10.244.1.8:8080 enabled
server SRV_3 10.244.7.23:8080 enabled
server SRV_4 127.0.0.1:1 disabled
haproxy-ingress-7cc59c8d86-vhqgk
backend zz_svc_yy-vvv_http from haproxytech
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check
server SRV_1 10.244.7.22:8080 enabled
server SRV_2 10.244.1.8:8080 enabled
server SRV_3 10.244.7.23:8080 enabled
server SRV_4 127.0.0.1:1 disabled
haproxy-ingress-7cc59c8d86-bfsl5
backend zz_svc_yy-vvv_http from haproxytech
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check
server SRV_1 10.244.1.8:8080 enabled
server SRV_2 10.244.7.22:8080 enabled
server SRV_3 10.244.7.23:8080 enabled
server SRV_4 127.0.0.1:1 disabled
haproxy-ingress-7cc59c8d86-pvb7p
backend zz_svc_yy-vvv_http from haproxytech
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check
server SRV_1 10.244.1.8:8080 enabled
server SRV_2 10.244.7.22:8080 enabled
server SRV_3 10.244.7.23:8080 enabled
server SRV_4 127.0.0.1:1 disabled
So the file on disk converges, but the live backend state does not.
Before/after haproxy.cfg from one ingress pod
To demonstrate that the stale addresses are from the previous deployment:
Before redeploy of application
backend zz_svc_yy-vvv_http from haproxytech
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check
server SRV_1 127.0.0.1:1 disabled
server SRV_2 10.244.2.114:8080 enabled
server SRV_3 10.244.0.36:8080 enabled
server SRV_4 10.244.2.113:8080 enabled
server SRV_5 127.0.0.1:1 disabled
After redeploy of application
backend zz_svc_yy-vvv_http from haproxytech
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check
server SRV_1 10.244.1.8:8080 enabled
server SRV_2 10.244.7.22:8080 enabled
server SRV_3 10.244.7.23:8080 enabled
server SRV_4 127.0.0.1:1 disabled
Local conditions
This ingress is running in production under steady load of roughly 200 requests/second and handles that normally without any problems.
Because of that, load may be part of the trigger even though the setup is generally stable at this traffic level.
We are seeing this while doing multiple simultaneous deployments. Maybe it could be related to #768, that also occur during 'mass pod restart'.
Description
We are seeing inconsistent live backend state between HAProxy Kubernetes Ingress replicas after redeploying an application behind a Service.
The generated haproxy.cfg on disk is updated correctly on all ingress pods after the redeploy, but the running HAProxy backend state is not updated on all pods. Some ingress replicas keep stale backend pod IPs in the live runtime state, mark them L4TOUT, and return 503. Other ingress replicas have the correct backend list and work normally.
As a workaround, adding:
haproxy.org/standalone-backend: "true"to the Ingress makes the live backend update correctly after redeploy, and the problem disappears in our testing.
Environment
haproxytech/kubernetes-ingress chart version: 1.49.0HAProxy Kubernetes Ingress values
Observed problem
During or after redeploy of an application behind a Service, some HAProxy ingress replicas continue to use stale backend pod IPs in the live backend state.
Symptoms:
We initially saw this as intermittent 503 during redeploys of multiple simultaneous deployments and sometimes after pod termination events.
Evidence that generated config is correct, but runtime state is wrong
Runtime/stats output differs between HAProxy replicas
From the stats endpoint on each HAProxy ingress pod for backend zz_svc_yy-vvv_http:
haproxy-ingress-7cc59c8d86-kkj78
haproxy-ingress-7cc59c8d86-vhqgk
haproxy-ingress-7cc59c8d86-bfsl5
haproxy-ingress-7cc59c8d86-pvb7p
These are not aligned across replicas, even though they are the same backend.
On-disk config is aligned across replicas
On-disk
haproxy.cfgon the same pods:haproxy-ingress-7cc59c8d86-kkj78haproxy-ingress-7cc59c8d86-vhqgkhaproxy-ingress-7cc59c8d86-bfsl5haproxy-ingress-7cc59c8d86-pvb7pSo the file on disk converges, but the live backend state does not.
Before/after
haproxy.cfgfrom one ingress podTo demonstrate that the stale addresses are from the previous deployment:
Before redeploy of application
After redeploy of application
Local conditions
This ingress is running in production under steady load of roughly 200 requests/second and handles that normally without any problems.
Because of that, load may be part of the trigger even though the setup is generally stable at this traffic level.
We are seeing this while doing multiple simultaneous deployments. Maybe it could be related to #768, that also occur during 'mass pod restart'.