Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions docs/en_US/container_deployment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -564,3 +564,78 @@ the container is typically launched per the example below:
-e "SCRIPT_NAME=/pgadmin4" \
-l "traefik.frontend.pgadmin4.rule=Host(`host.example.com`) && PathPrefix(`/pgadmin4`)" \
-d dpage/pgadmin4

Sharing the data volume across containers (Kubernetes init containers)
----------------------------------------------------------------------

A common Kubernetes pattern is to bootstrap a pgAdmin deployment with one or
more init containers that share the ``/var/lib/pgadmin`` volume with the main
pgAdmin container — for example, an init container that runs
``setup.py load-servers`` to import a ``servers.json`` definition file at
each rollout.

**The image tag of any such sidecar/init container must NOT be newer than
the main pgAdmin container's tag.** pgAdmin's configuration database
(``pgadmin4.db``) is migrated forward only — destructive operations such as
dropping a column are part of normal upgrades. If an init container running
``pgadmin4:latest`` (or any newer tag) executes ``setup.py`` against a
``pgadmin4.db`` that the main, older pgAdmin will then read, the init
container's migrations will advance the schema past what the main container's
ORM understands, and the main container will fail at runtime with errors
like ``no such column: <table>.<column>``.

The safe configuration is to pin **both** the main container and every
sidecar/init container that touches the data volume to the **same**
explicit version tag, and upgrade them together:

.. code-block:: yaml

# In your Helm values / Deployment spec:
image: docker.io/dpage/pgadmin4:9.14 # main pgAdmin container
...
extraInitContainers:
- name: import-servers-json
# Match the main container's tag exactly. Do NOT use :latest.
image: docker.io/dpage/pgadmin4:9.14
# ... rest of the init container spec ...
Comment on lines +593 to +600
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify Helm values vs Deployment-spec YAML to avoid invalid chart configuration.

The examples at Line 593 and Line 634 are labeled as “Helm values / Deployment spec” but use Deployment-style fields (image: ..., spec.strategy.type). In this repo’s Helm chart, image and strategy come from values keys (image.registry/repository/tag and strategy.type), so readers may paste invalid values into Helm. Please split into two explicit snippets (Helm values vs raw Deployment manifest) or use Helm-values-native keys only.

Also applies to: 634-637

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/en_US/container_deployment.rst` around lines 593 - 600, Update the
examples so Helm-values keys are not mixed with raw Deployment fields: either
split the shown snippets into two labeled blocks (one demonstrating Helm values
using keys like image.registry, image.repository, image.tag and strategy.type in
values.yaml, and a separate raw Deployment manifest showing image:
docker.io/dpage/pgadmin4:9.14, spec.strategy.type, and extraInitContainers), or
replace the current examples with Helm-values-native keys only (remove
Deployment-style fields such as image: docker.io/dpage/pgadmin4:9.14 and
spec.strategy.type from the values example and instead show
image.registry/repository/tag and strategy.type). Ensure the same change is
applied to the other occurrence noted (the snippet around spec.strategy.type).


When upgrading pgAdmin in such a deployment, change every reference to the
image tag at the same time so that the main container and any sidecar/init
containers move forward together.

Use ``strategy: Recreate``, not ``RollingUpdate``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Even when every container's image tag is pinned correctly, **a rolling
upgrade across pgAdmin versions is unsafe** when the old and new pods share
a data volume. Kubernetes' default ``RollingUpdate`` strategy starts the
new pod, waits for it to become healthy, and only *then* terminates the
old pod. During that overlap window:

1. The new pod's startup runs ``db_upgrade()`` and applies any pending
migrations to the shared ``pgadmin4.db`` — including destructive ones
(column drops, table renames, type changes).
2. The new pod becomes healthy. The old pod is still alive and still has
``pgadmin4.db`` open with its older ORM schema metadata.
3. Until Kubernetes terminates the old pod, requests routed to it
generate queries that reference the pre-migration schema. Those
queries now fail at runtime against the migrated database — for
example, ``no such column: <table>.<column>`` when a column was
dropped in this release.

Because pgAdmin's migrations are forward-only with single-step destructive
operations (a column dropped in release N+1 is gone immediately, not after
a deprecation cycle), there is no safe way for an N-version pod to keep
serving against a migrated N+1 schema. Set the deployment strategy to
``Recreate``, which terminates the old pod *before* starting the new one:

.. code-block:: yaml

spec:
strategy:
type: Recreate # not RollingUpdate

The trade-off is a few seconds of downtime during each upgrade, in
exchange for not serving traffic from a pod whose ORM is misaligned with
the database schema underneath it. This is the supported upgrade
strategy for pgAdmin K8s deployments today.
Loading