This is an automated email from the ASF dual-hosted git repository.
Miretpl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 2a1961ac68c Allow extra init containers for PgBouncer (#74612)
2a1961ac68c is described below
commit 2a1961ac68c09f2523614736b653d66908262ed6
Author: Arkadiusz Bach <[email protected]>
AuthorDate: Fri Nov 6 22:49:12 2026 +0100
Allow extra init containers for PgBouncer (#74612)
Azure Database for PostgreSQL deployments using Microsoft Entra ID need
credentials before PgBouncer starts and must refresh them while it runs.
Ordinary sidecars cannot guarantee that initialization has finished before
PgBouncer starts. User-provided init containers, including native sidecars
with startup probes, make this deployment pattern possible.
Co-authored-by: Przemysław Mirowski
<[email protected]>
---
chart/docs/using-additional-containers.rst | 11 +++-
.../templates/pgbouncer/pgbouncer-deployment.yaml | 4 ++
chart/tests/helm_tests/other/test_pgbouncer.py | 70 ++++++++++++++++++++++
chart/values.schema.json | 8 +++
chart/values.yaml | 3 +
5 files changed, 94 insertions(+), 2 deletions(-)
diff --git a/chart/docs/using-additional-containers.rst
b/chart/docs/using-additional-containers.rst
index 5c8789a7f8d..0c1be66c168 100644
--- a/chart/docs/using-additional-containers.rst
+++ b/chart/docs/using-additional-containers.rst
@@ -22,7 +22,7 @@ Sidecar Containers
------------------
If you want to deploy your own sidecar container, you can add it through the
``extraContainers`` parameter.
-You can define different containers for the scheduler, api-server,
Kubernetes/Celery workers, triggerer, dag processor, flower, create user job
and migrate database job pods.
+You can define different containers for the scheduler, api-server,
Kubernetes/Celery workers, triggerer, dag processor, flower, PgBouncer, create
user job and migrate database job pods.
For example, sidecars that sync Dags from object storage:
@@ -52,7 +52,14 @@ Init Containers
---------------
You can also deploy extra init containers through the ``extraInitContainers``
parameter.
-You can define different containers for the scheduler, api-server,
Celery/Kubernetes workers, triggerer, dag processor, create user job and
migrate database job pods.
+You can define different containers for the scheduler, api-server,
Celery/Kubernetes workers, triggerer, dag processor, PgBouncer, create user job
and migrate database job pods.
+
+For example, ``pgbouncer.extraInitContainers`` can run a user-provided
credential refresher for Azure Database
+for PostgreSQL authentication with short-lived Microsoft Entra ID tokens. The
credentials must be obtained before PgBouncer
+starts and refreshed while it runs. On clusters supporting `native Kubernetes
sidecars
+<https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/>`_,
use ``restartPolicy: Always``
+and a ``startupProbe`` that succeeds only after the initial credentials are
ready. This lets the refresher
+continue running while PgBouncer starts after successful initialization.
For example, an init container that just says hello:
diff --git a/chart/templates/pgbouncer/pgbouncer-deployment.yaml
b/chart/templates/pgbouncer/pgbouncer-deployment.yaml
index fd67adceee5..279927cfa06 100644
--- a/chart/templates/pgbouncer/pgbouncer-deployment.yaml
+++ b/chart/templates/pgbouncer/pgbouncer-deployment.yaml
@@ -95,6 +95,10 @@ spec:
{{- end }}
restartPolicy: Always
imagePullSecrets: {{- include "image_pull_secrets" . | nindent 8 }}
+ {{- if .Values.pgbouncer.extraInitContainers }}
+ initContainers:
+ {{- tpl (toYaml .Values.pgbouncer.extraInitContainers) . | nindent 8 }}
+ {{- end }}
containers:
- name: pgbouncer
image: {{ template "pgbouncer_image" . }}
diff --git a/chart/tests/helm_tests/other/test_pgbouncer.py
b/chart/tests/helm_tests/other/test_pgbouncer.py
index 29d10f7d895..27699a00833 100644
--- a/chart/tests/helm_tests/other/test_pgbouncer.py
+++ b/chart/tests/helm_tests/other/test_pgbouncer.py
@@ -42,6 +42,76 @@ class TestPgbouncer:
assert jmespath.search("kind", docs[0]) == "Deployment"
assert jmespath.search("metadata.name", docs[0]) ==
"release-name-pgbouncer"
assert jmespath.search("spec.template.spec.containers[0].name",
docs[0]) == "pgbouncer"
+ assert "initContainers" not in jmespath.search("spec.template.spec",
docs[0])
+
+ def test_should_not_add_empty_extra_init_containers(self):
+ docs = render_chart(
+ values={"pgbouncer": {"enabled": True, "extraInitContainers": []}},
+ show_only=["templates/pgbouncer/pgbouncer-deployment.yaml"],
+ )
+
+ assert "initContainers" not in jmespath.search("spec.template.spec",
docs[0])
+
+ @pytest.mark.parametrize(
+ "extra_init_container",
+ [
+ {
+ "name": "test-init-container",
+ "image": "test-registry/test-repo:test-tag",
+ "volumeMounts": [{"name": "pgbouncer-auth", "mountPath":
"/etc/pgbouncer/auth"}],
+ },
+ {
+ "name": "token-refresher",
+ "image": "test-registry/token-refresher:test-tag",
+ "restartPolicy": "Always",
+ "startupProbe": {
+ "exec": {"command": ["sh", "-c", "test -s
/etc/pgbouncer/auth/userlist.txt"]},
+ },
+ "volumeMounts": [{"name": "pgbouncer-auth", "mountPath":
"/etc/pgbouncer/auth"}],
+ },
+ ],
+ ids=["standard-init-container", "restartable-init-container"],
+ )
+ def test_should_add_extra_init_containers(self, extra_init_container):
+ docs = render_chart(
+ values={
+ "pgbouncer": {
+ "enabled": True,
+ "extraInitContainers": [extra_init_container],
+ "extraVolumes": [{"name": "pgbouncer-auth", "emptyDir":
{}}],
+ "extraVolumeMounts": [
+ {"name": "pgbouncer-auth", "mountPath":
"/etc/pgbouncer/auth"},
+ ],
+ },
+ },
+ show_only=["templates/pgbouncer/pgbouncer-deployment.yaml"],
+ )
+
+ assert jmespath.search("spec.template.spec.initContainers", docs[0])
== [extra_init_container]
+
+ def test_should_template_extra_init_containers(self):
+ docs = render_chart(
+ values={
+ "images": {"pgbouncer": {"tag": "test-tag"}},
+ "pgbouncer": {
+ "enabled": True,
+ "extraInitContainers": [
+ {
+ "name": "{{ .Release.Name }}-token-refresher",
+ "image": "test-registry/token-refresher:{{
.Values.images.pgbouncer.tag }}",
+ },
+ ],
+ },
+ },
+ show_only=["templates/pgbouncer/pgbouncer-deployment.yaml"],
+ )
+
+ assert jmespath.search("spec.template.spec.initContainers", docs[0])
== [
+ {
+ "name": "release-name-token-refresher",
+ "image": "test-registry/token-refresher:test-tag",
+ },
+ ]
def test_should_create_pgbouncer_service(self):
docs = render_chart(
diff --git a/chart/values.schema.json b/chart/values.schema.json
index 04b95c4cf83..de50eaca82f 100644
--- a/chart/values.schema.json
+++ b/chart/values.schema.json
@@ -7946,6 +7946,14 @@
"$ref": "#/definitions/io.k8s.api.core.v1.Container"
}
},
+ "extraInitContainers": {
+ "description": "Add additional init containers into
PgBouncer pod (templated).",
+ "type": "array",
+ "default": [],
+ "items": {
+ "$ref": "#/definitions/io.k8s.api.core.v1.Container"
+ }
+ },
"serviceAccount": {
"description": "Create ServiceAccount.",
"type": "object",
diff --git a/chart/values.yaml b/chart/values.yaml
index 3edecf5ad95..ae296a5f034 100644
--- a/chart/values.yaml
+++ b/chart/values.yaml
@@ -2889,6 +2889,9 @@ pgbouncer:
# Launch additional containers into PgBouncer pod.
extraContainers: []
+ # Add additional init containers into PgBouncer pod (templated).
+ extraInitContainers: []
+
# Select certain nodes for PgBouncer pods.
nodeSelector: {}
affinity: {}