From 5a6cdc32732f977326ccd6b7bfff2dbb329b1e1f Mon Sep 17 00:00:00 2001 From: Brian Suh Date: Mon, 29 Jun 2026 19:02:42 -0700 Subject: [PATCH] Deliver HAProxy config via writable emptyDir so #PUBLIC_IP substitution works (v1.3.3) Since #483 mounted haproxy.cfg directly from a ConfigMap, the container entrypoint (set_public_ip_and_start.sh) could no longer rewrite the config: ConfigMap volumes (and subPath file mounts) are always mounted read-only by the kubelet regardless of the readOnly flag, so its in-place sed -i 's/#PUBLIC_IP/tcp-request connection set-dst ipv4($PUBLIC_IP)/g' failed with 'Resource busy' / read-only filesystem. The #PUBLIC_IP placeholders were left untouched, HAProxy never set the destination address, and it advertised each pod's private IP to WhatsApp instead of the public egress IP (observed server-side as 'proxy IP address is unexpected: 10.0.x.x'). Fix, chart-only (no image rebuild): - Mount the ConfigMap read-only at a side path (/haproxy-config-src). - Mount a writable emptyDir at the canonical /usr/local/etc/haproxy. - An initContainer seeds the emptyDir with the image defaults (preserving errors/) and overlays the ConfigMap haproxy.cfg. The entrypoint can now edit haproxy.cfg in place at its normal location, so the config stays inspectable via the usual path and HAProxy advertises the real public IP again. Bump chart version to 1.3.3. --- charts/whatsapp-proxy-chart/Chart.yaml | 2 +- .../templates/deployment.yaml | 34 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/charts/whatsapp-proxy-chart/Chart.yaml b/charts/whatsapp-proxy-chart/Chart.yaml index e34182e..0a16359 100644 --- a/charts/whatsapp-proxy-chart/Chart.yaml +++ b/charts/whatsapp-proxy-chart/Chart.yaml @@ -17,7 +17,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.3.2 +version: 1.3.3 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/whatsapp-proxy-chart/templates/deployment.yaml b/charts/whatsapp-proxy-chart/templates/deployment.yaml index d6c92d2..57494e3 100644 --- a/charts/whatsapp-proxy-chart/templates/deployment.yaml +++ b/charts/whatsapp-proxy-chart/templates/deployment.yaml @@ -32,6 +32,29 @@ spec: serviceAccountName: {{ include "whatsapp-proxy-chart.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + # The container entrypoint substitutes #PUBLIC_IP -> `set-dst` in + # /usr/local/etc/haproxy/haproxy.cfg in place. A ConfigMap volume is + # always mounted read-only by the kubelet (the readOnly flag can't + # change that), which makes that in-place edit fail and leaves HAProxy + # advertising the pod's private IP. So seed a writable emptyDir with the + # image defaults (e.g. errors/) and overlay the ConfigMap haproxy.cfg. + - name: haproxy-config-init + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /bin/sh + - -c + - | + set -e + cp -a /usr/local/etc/haproxy/. /haproxy-runtime/ + cp /haproxy-config-src/haproxy.cfg /haproxy-runtime/haproxy.cfg + volumeMounts: + - name: haproxy-config-src + mountPath: /haproxy-config-src + readOnly: true + - name: haproxy-config + mountPath: /haproxy-runtime containers: - name: {{ .Chart.Name }} securityContext: @@ -96,14 +119,17 @@ spec: - name: "PUBLIC_IP" value: "{{ .Values.public_ip }}" volumeMounts: + # Writable copy of the config dir (populated by the initContainer) + # so the entrypoint can edit haproxy.cfg in place, while keeping it + # at its canonical /usr/local/etc/haproxy/haproxy.cfg location. - name: haproxy-config - mountPath: /usr/local/etc/haproxy/haproxy.cfg - subPath: haproxy.cfg - readOnly: true + mountPath: /usr/local/etc/haproxy volumes: - - name: haproxy-config + - name: haproxy-config-src configMap: name: {{ include "whatsapp-proxy-chart.fullname" . }}-haproxy + - name: haproxy-config + emptyDir: {} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }}