mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-08-17 16:34:44 -05:00
Corrected "varible" -> "variable" and rewrote the broken sentence to explain that PGPASS_FILE is the path to a pgpass file that is copied into the container and used as the .pgpass file.
649 lines
24 KiB
ReStructuredText
649 lines
24 KiB
ReStructuredText
.. _container_deployment:
|
|
|
|
*****************************
|
|
`Container Deployment`:index:
|
|
*****************************
|
|
|
|
pgAdmin can be deployed in a container using the image at:
|
|
|
|
https://hub.docker.com/r/dpage/pgadmin4/
|
|
|
|
There are various tags that you can select from to get the version of pgAdmin
|
|
that you want, using a command such as this if you're using Docker:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4:<tag name>
|
|
|
|
where *<tag name>* is one of the following:
|
|
|
|
.. table::
|
|
:class: longtable
|
|
:widths: 1 4
|
|
|
|
+----------+-------------------------------------------------------------------------------+
|
|
| Tag name | Description |
|
|
+==========+===============================================================================+
|
|
| latest | The most recent release. |
|
|
+----------+-------------------------------------------------------------------------------+
|
|
| 8.4 | A specific version (8.4 in this case). |
|
|
+----------+-------------------------------------------------------------------------------+
|
|
| 8 | the latest release of a specific major version (major version 8 in this case).|
|
|
+----------+-------------------------------------------------------------------------------+
|
|
| snapshot | The latest nightly test build. |
|
|
+----------+-------------------------------------------------------------------------------+
|
|
|
|
PostgreSQL Utilities
|
|
********************
|
|
|
|
The PostgreSQL utilities *pg_dump*, *pg_dumpall*, *pg_restore* and *psql* are
|
|
included in the container to allow backups to be created and restored and other
|
|
maintenance functions to be executed. Multiple versions are included in the
|
|
following directories to allow use with different versions of the database
|
|
server:
|
|
|
|
* PostgreSQL 12: */usr/local/pgsql-12*
|
|
* PostgreSQL 13: */usr/local/pgsql-13*
|
|
* PostgreSQL 14: */usr/local/pgsql-14*
|
|
* PostgreSQL 15: */usr/local/pgsql-15*
|
|
* PostgreSQL 16: */usr/local/pgsql-16*
|
|
|
|
The default binary paths set in the container are as follows:
|
|
|
|
.. code-block:: bash
|
|
|
|
DEFAULT_BINARY_PATHS = {
|
|
'pg-18': '/usr/local/pgsql-18',
|
|
'pg-17': '/usr/local/pgsql-17',
|
|
'pg-16': '/usr/local/pgsql-16',
|
|
'pg-15': '/usr/local/pgsql-15',
|
|
'pg-14': '/usr/local/pgsql-14',
|
|
'pg-13': '/usr/local/pgsql-13'
|
|
}
|
|
|
|
this may be changed in the :ref:`preferences`.
|
|
|
|
Environment Variables
|
|
*********************
|
|
|
|
The container will accept the following variables at startup:
|
|
|
|
**PGADMIN_DEFAULT_EMAIL**
|
|
|
|
This is the email address used when setting up the initial administrator account
|
|
to login to pgAdmin. This variable is required and must be set at launch time.
|
|
|
|
**PGADMIN_DEFAULT_PASSWORD**
|
|
|
|
This is the password used when setting up the initial administrator account to
|
|
login to pgAdmin. This variable is required and must be set at launch time.
|
|
|
|
**PGADMIN_DEFAULT_PASSWORD_FILE**
|
|
|
|
This is the password used when setting up the initial administrator account to
|
|
login to pgAdmin. This value should be set to *docker secret* in order to set
|
|
the password. This variable is supported in docker swarm environment or while creating
|
|
container with docker compose. PGADMIN_DEFAULT_PASSWORD or PGADMIN_DEFAULT_PASSWORD_FILE
|
|
variable is required and must be set at launch time.
|
|
|
|
**PGADMIN_DISABLE_POSTFIX**
|
|
|
|
*Default: <null>*
|
|
|
|
If left unset, a Postfix server will be started to deliver password reset
|
|
emails.
|
|
|
|
If set to any value, the Postfix server will not be started, and pgAdmin will
|
|
need to be configured to use an external mail server using the *PGADMIN_CONFIG_*
|
|
options below.
|
|
|
|
This option is useful if you're running in an environment that prevents the use
|
|
of sudo to start Postfix, or if you wish to use an external mail server.
|
|
|
|
**PGADMIN_ENABLE_TLS**
|
|
|
|
*Default: <null>*
|
|
|
|
If left un-set, the container will listen on port 80 for connections in plain
|
|
text. If set to any value, the container will listen on port 443 for TLS
|
|
connections.
|
|
|
|
When TLS is enabled, a certificate and key must be provided. Typically these
|
|
should be stored on the host file system and mounted from the container. The
|
|
expected paths are /certs/server.cert and /certs/server.key
|
|
|
|
**PGADMIN_LISTEN_ADDRESS**
|
|
|
|
*Default: [::]*
|
|
|
|
Specify the local address that the servers listens on. The default should work
|
|
for most users - in IPv4-only environments, this may need to be set to
|
|
0.0.0.0.
|
|
|
|
**PGADMIN_LISTEN_PORT**
|
|
|
|
*Default: 80 or 443 (if TLS is enabled)*
|
|
|
|
Allows the port that the server listens on to be set to a specific value rather
|
|
than using the default.
|
|
|
|
**PGADMIN_SERVER_JSON_FILE**
|
|
|
|
*Default: /pgadmin4/servers.json*
|
|
|
|
Override the default file path for the server definition list. See the
|
|
/pgadmin4/servers.json mapped file below for more information. See the format
|
|
of the `Servers JSON file <https://www.pgadmin.org/docs/pgadmin4/latest/import_export_servers.html#json-format>`_.
|
|
|
|
**PGADMIN_REPLACE_SERVERS_ON_STARTUP**
|
|
|
|
*Default: null*
|
|
|
|
By default, the server definitions are only loaded on first launch, i.e. when initializing the configuration database. See PGADMIN_SERVER_JSON_FILE above.
|
|
|
|
If this variable is set to True, the server definitions will be replaced on every launch. This can be used to declaratively manage the server definitions.
|
|
|
|
**PGADMIN_PREFERENCES_JSON_FILE**
|
|
|
|
*Default: /pgadmin4/preferences.json*
|
|
|
|
Override the default file path for the preferences customization at the container creation. See the
|
|
/pgadmin4/preferences.json mapped file below for more information. See the format
|
|
of the `Preferences JSON file <https://www.pgadmin.org/docs/pgadmin4/latest/preferences.html#json-format>`_.
|
|
|
|
**PGADMIN_CUSTOM_CONFIG_DISTRO_FILE**
|
|
|
|
*Default: /pgadmin4/config_distro.py*
|
|
|
|
Override the default file path for the pgadmin configurations file.This can be used while provisioning
|
|
container with read only root file system to achieve a more secure pgadmin4 deployment for kubernetes.
|
|
Note that if you are externally mapping this file, then environment variables passed using *PGADMIN_CONFIG_*
|
|
suffix will be ignored.
|
|
|
|
**PGPASS_FILE**
|
|
|
|
*Default: <null>*
|
|
Set this variable to the path of a pgpass file if you want to supply passwords
|
|
for the servers added in pgAdmin. On startup, the file is copied into the
|
|
container and used as the ``.pgpass`` file.
|
|
|
|
**GUNICORN_ACCESS_LOGFILE**
|
|
|
|
*Default: -* (stdout)
|
|
|
|
Specify an output file in which to store the Gunicorn access logs, instead of
|
|
sending them to stdout.
|
|
|
|
**GUNICORN_LIMIT_REQUEST_LINE**
|
|
|
|
*Default: 8190*
|
|
|
|
Set the maximum size of HTTP request line in bytes. By default the pgAdmin
|
|
container uses the maximum limited size offered by Gunicorn as some requests
|
|
can be quite large. In exceptional cases this value can be set to 0 (zero) to
|
|
specify "unlimited", however this poses a potential denial of service hazard.
|
|
|
|
**GUNICORN_THREADS**
|
|
|
|
*Default: 25*
|
|
|
|
Adjust the number of threads the Gunicorn server uses to handle incoming
|
|
requests. This should typically be left as-is, except in highly loaded systems
|
|
where it may be increased.
|
|
|
|
**PGADMIN_CONFIG_***
|
|
|
|
This is a variable prefix that can be used to override any of the configuration
|
|
options in pgAdmin's *config.py* file. Add the *PGADMIN_CONFIG_* prefix to any
|
|
variable name from *config.py* and give the value in the format 'string value'
|
|
for strings, True/False for booleans or 123 for numbers. See below for an
|
|
example.
|
|
|
|
Settings are written to */pgadmin4/config_distro.py* within the container, which
|
|
is read after */pgadmin4/config.py* and before */pgadmin4/config_local.py*.
|
|
Any settings given will therefore override anything in config.py, but can be
|
|
overridden by settings in config_local.py.
|
|
|
|
Settings are only written to */pgadmin4/config_distro.py* once, typically on
|
|
first launch of the container. If */pgadmin4/config_distro.py* contains one or
|
|
more lines, then no changes are made; for example, if the container instance is
|
|
restarted, or */pgadmin4/config_distro.py* is mapped to a file on persistent
|
|
storage (not recommended - use */pgadmin4/config_local.py* instead)!
|
|
|
|
See :ref:`config_py` for more information on the available configuration settings.
|
|
|
|
Mapped Files and Directories
|
|
****************************
|
|
|
|
The following files or directories can be mapped from the container onto the
|
|
host machine to allow configuration to be customised and shared between
|
|
instances.
|
|
|
|
.. warning:: Warning: pgAdmin runs as the *pgadmin* user (UID: 5050) in the
|
|
*pgadmin* group (GID: 5050) in the container. You must ensure that all files
|
|
are readable, and where necessary (e.g. the working/session directory)
|
|
writeable for this user on the host machine. For example:
|
|
|
|
.. code-block:: bash
|
|
|
|
sudo chown -R 5050:5050 <host_directory>
|
|
|
|
On some filesystems that do not support extended attributes, it may not be
|
|
possible to run pgAdmin without specifying a value for *PGADMIN_LISTEN_PORT*
|
|
that is greater than 1024. In such cases, specify an alternate port when
|
|
launching the container by adding the environment variable, for example:
|
|
|
|
.. code-block:: bash
|
|
|
|
-e 'PGADMIN_LISTEN_PORT=5050'
|
|
|
|
Don't forget to adjust any host-container port mapping accordingly.
|
|
|
|
**/var/lib/pgadmin**
|
|
|
|
This is the working directory in which pgAdmin stores session data, user files,
|
|
configuration files, and it's configuration database. Mapping this directory
|
|
onto the host machine gives you an easy way to maintain configuration between
|
|
invocations of the container.
|
|
|
|
**/pgadmin4/config_local.py**
|
|
|
|
This file can be used to override configuration settings in pgAdmin. Settings
|
|
found in config.py can be overridden with deployment specific values if
|
|
required. Settings in config_local.py will also override anything specified in
|
|
the container environment through *PGADMIN_CONFIG_* prefixed variables.
|
|
|
|
**/pgadmin4/servers.json**
|
|
|
|
If this file is mapped, server definitions found in it will be loaded at launch
|
|
time. This allows connection information to be pre-loaded into the instance of
|
|
pgAdmin in the container. Note that server definitions are only loaded on first
|
|
launch, i.e. when the configuration database is created, and not on subsequent
|
|
launches using the same configuration database.
|
|
|
|
**/pgadmin4/preferences.json**
|
|
|
|
If this file is mapped, preferences defined in it will be updated at launch
|
|
time. This allows customization of preferences settings into the instance of
|
|
pgAdmin in the container. Note that preferences are only set on first
|
|
launch, i.e. when the configuration database is created, and not on subsequent
|
|
launches using the same configuration database.
|
|
|
|
**/certs/server.cert**
|
|
|
|
If TLS is enabled, this file will be used as the servers TLS certificate.
|
|
|
|
**/certs/server.key**
|
|
|
|
If TLS is enabled, this file will be used as the key file for the servers TLS
|
|
certificate.
|
|
|
|
Examples
|
|
********
|
|
|
|
Run a simple container over port 80:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run -p 80:80 \
|
|
-e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' \
|
|
-e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' \
|
|
-d dpage/pgadmin4
|
|
|
|
Run a simple container over port 80, setting some configuration options:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run -p 80:80 \
|
|
-e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' \
|
|
-e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' \
|
|
-e 'PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION=True' \
|
|
-e 'PGADMIN_CONFIG_LOGIN_BANNER="Authorised users only!"' \
|
|
-e 'PGADMIN_CONFIG_CONSOLE_LOG_LEVEL=10' \
|
|
-d dpage/pgadmin4
|
|
|
|
Run a TLS secured container using a shared config/storage directory in
|
|
/private/var/lib/pgadmin on the host, and servers pre-loaded from
|
|
/tmp/servers.json on the host:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run -p 443:443 \
|
|
-v /private/var/lib/pgadmin:/var/lib/pgadmin \
|
|
-v /path/to/certificate.cert:/certs/server.cert \
|
|
-v /path/to/certificate.key:/certs/server.key \
|
|
-v /tmp/servers.json:/pgadmin4/servers.json \
|
|
-e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' \
|
|
-e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' \
|
|
-e 'PGADMIN_ENABLE_TLS=True' \
|
|
-d dpage/pgadmin4
|
|
|
|
Restricted Security Contexts (OpenShift, ``--cap-drop=ALL``)
|
|
************************************************************
|
|
|
|
Some platforms refuse to honor Linux file capabilities. The two situations
|
|
the pgAdmin container handles automatically are:
|
|
|
|
- ``--cap-drop=ALL`` (or an equivalent restricted Kubernetes SecurityContext
|
|
such as OpenShift's ``restricted-v2`` SCC), which zeros the bounding set
|
|
and removes ``CAP_NET_BIND_SERVICE``. Exec of a capability-tagged binary
|
|
then fails with ``Operation not permitted``.
|
|
|
|
- ``--security-opt=no-new-privileges`` (or
|
|
``allowPrivilegeEscalation: false``), which causes the kernel to silently
|
|
strip file capabilities on exec. The binary runs, but a subsequent
|
|
``bind()`` to a port below 1024 fails with ``EPERM``.
|
|
|
|
The container's entrypoint reads ``/proc/self/status`` at startup, detects
|
|
either condition, switches gunicorn to the non-capability python
|
|
interpreter, and (when *PGADMIN_LISTEN_PORT* is not set) defaults the
|
|
listen port to **8080** for plain HTTP and **8443** for TLS instead of
|
|
80/443. A message is logged so the choice is visible.
|
|
|
|
In practice this means a typical OpenShift deployment requires no special
|
|
build, no setcap, and no custom configuration — only a Service / Route
|
|
that targets the chosen non-privileged port:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker run --rm -p 8080:8080 \
|
|
--security-opt=no-new-privileges \
|
|
--cap-drop=ALL \
|
|
-e 'PGADMIN_DEFAULT_EMAIL=user@domain.com' \
|
|
-e 'PGADMIN_DEFAULT_PASSWORD=SuperSecret' \
|
|
dpage/pgadmin4
|
|
|
|
If you explicitly set *PGADMIN_LISTEN_PORT*, that value is honored in both
|
|
the restricted and unrestricted paths.
|
|
|
|
Reverse Proxying
|
|
****************
|
|
|
|
Sometimes it's desirable to have users connect to pgAdmin through a reverse
|
|
proxy rather than directly to the container it's running in. The following
|
|
examples show how this can be achieved. With traditional reverse proxy servers
|
|
such as `Nginx <https://www.nginx.com/>`_, pgAdmin is running in a container on
|
|
the same host, with port 5050 on the host mapped to port 80 on the container,
|
|
for example:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run -p 5050:80 \
|
|
-e "PGADMIN_DEFAULT_EMAIL=user@domain.com" \
|
|
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
|
|
-d dpage/pgadmin4
|
|
|
|
pgAdmin X-Forwarded-* Configuration
|
|
-----------------------------------
|
|
|
|
pgAdmin needs to understand how many proxies set each header so it knows what
|
|
values to trust. The configuration parameters for the X-Forwarded-* options
|
|
which are used for this purpose are shown below, along with their default
|
|
values.
|
|
|
|
pgAdmin is configured by default to be able to run behind a reverse proxy even
|
|
on a non-standard port and these config options don't normally need to be
|
|
changed. If you're running an unusual configuration (such as multiple reverse
|
|
proxies) you can adjust the configuration to suit.
|
|
|
|
.. code-block:: python
|
|
|
|
# Number of values to trust for X-Forwarded-For
|
|
PROXY_X_FOR_COUNT = 1
|
|
|
|
# Number of values to trust for X-Forwarded-Proto.
|
|
PROXY_X_PROTO_COUNT = 0
|
|
|
|
# Number of values to trust for X-Forwarded-Host.
|
|
PROXY_X_HOST_COUNT = 0
|
|
|
|
# Number of values to trust for X-Forwarded-Port.
|
|
PROXY_X_PORT_COUNT = 1
|
|
|
|
# Number of values to trust for X-Forwarded-Prefix.
|
|
PROXY_X_PREFIX_COUNT = 0
|
|
|
|
HTTP via Nginx
|
|
--------------
|
|
|
|
A configuration similar to the following can be used to create a simple HTTP
|
|
reverse proxy listening for all hostnames with `Nginx
|
|
<https://www.nginx.com/>`_:
|
|
|
|
.. code-block:: nginx
|
|
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
|
|
location / {
|
|
proxy_set_header Host $host;
|
|
proxy_pass http://localhost:5050/;
|
|
proxy_redirect off;
|
|
}
|
|
}
|
|
|
|
If you wish to host pgAdmin under a subdirectory rather than on the root of the
|
|
server, you must specify the location and set the *X-Script-Name* header which
|
|
tells the pgAdmin container how to rewrite paths:
|
|
|
|
.. code-block:: nginx
|
|
|
|
server {
|
|
listen 80;
|
|
server_name _;
|
|
|
|
location /pgadmin4/ {
|
|
proxy_set_header X-Script-Name /pgadmin4;
|
|
proxy_set_header Host $host;
|
|
proxy_pass http://localhost:5050/;
|
|
proxy_redirect off;
|
|
}
|
|
}
|
|
|
|
If Nginx is also running in a container, there is no need to map the pgAdmin
|
|
port to the host, provided the two containers are running in the same Docker
|
|
network. In such a configuration, the *proxy_pass* option would be changed to
|
|
point to the pgAdmin container within the Docker network.
|
|
|
|
HTTPS via Nginx
|
|
---------------
|
|
|
|
The following configuration can be used to serve pgAdmin over HTTPS to the user
|
|
whilst the backend container is serving plain HTTP to the proxy server. In this
|
|
configuration we not only set *X-Script-Name*, but also *X-Scheme* to tell the
|
|
pgAdmin server to generate any URLs using the correct scheme. A redirect from
|
|
HTTP to HTTPS is also included. The certificate and key paths may need to be
|
|
adjusted as appropriate to the specific deployment:
|
|
|
|
.. code-block:: nginx
|
|
|
|
server {
|
|
listen 80;
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443;
|
|
server_name _;
|
|
|
|
ssl_certificate /etc/nginx/server.cert;
|
|
ssl_certificate_key /etc/nginx/server.key;
|
|
|
|
ssl on;
|
|
ssl_session_cache builtin:1000 shared:SSL:10m;
|
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
|
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
|
|
ssl_prefer_server_ciphers on;
|
|
|
|
location /pgadmin4/ {
|
|
proxy_set_header X-Script-Name /pgadmin4;
|
|
proxy_set_header X-Scheme $scheme;
|
|
proxy_set_header Host $host;
|
|
proxy_pass http://localhost:5050/;
|
|
proxy_redirect off;
|
|
}
|
|
}
|
|
|
|
Traefik
|
|
-------
|
|
|
|
Configuring `Traefik <https://traefik.io/>`_ is straightforward for either HTTP
|
|
or HTTPS when running pgAdmin in a container as it will automatically configure
|
|
itself to serve content from containers that are running on the local machine,
|
|
virtual hosting them at *<container_name>.<domain_name>*, where the domain
|
|
name is that specified in the Traefik configuration. The container is typically
|
|
launched per the example below:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run --name "pgadmin4" \
|
|
-e "PGADMIN_DEFAULT_EMAIL=user@domain.com" \
|
|
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
|
|
-d dpage/pgadmin4
|
|
|
|
Note that the TCP/IP port has not been mapped to the host as it was in the
|
|
Nginx example, and the container name has been set to a known value as it will
|
|
be used as the hostname and may need to be added to the DNS zone file.
|
|
|
|
The following configuration will listen on ports 80 and 443, redirecting 80 to
|
|
443, using the default certificate shipped with Traefik. See the Traefik
|
|
documentation for options to use certificates from LetsEncrypt or other issuers.
|
|
|
|
.. code-block:: ini
|
|
|
|
defaultEntryPoints = ["http", "https"]
|
|
|
|
[entryPoints]
|
|
[entryPoints.http]
|
|
address = ":80"
|
|
[entryPoints.http.redirect]
|
|
entryPoint = "https"
|
|
[entryPoints.https]
|
|
address = ":443"
|
|
[entryPoints.https.tls]
|
|
|
|
[docker]
|
|
domain = "domain_name"
|
|
watch = true
|
|
|
|
If you wish to host pgAdmin under a subdirectory using Traefik, the
|
|
configuration changes are typically made to the way the container is launched
|
|
and not to Traefik itself. For example, to host pgAdmin under */pgadmin4/*
|
|
instead of at the root directory, the Traefik configuration above may be used if
|
|
the container is launched like this while using the version v1 of Traefik:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run --name "pgadmin4" \
|
|
-e "PGADMIN_DEFAULT_EMAIL=user@domain.com" \
|
|
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
|
|
-e "SCRIPT_NAME=/pgadmin4" \
|
|
-l "traefik.frontend.rule=PathPrefix:/pgadmin4" \
|
|
-d dpage/pgadmin4
|
|
|
|
The *SCRIPT_NAME* environment variable has been set to tell the container it is
|
|
being hosted under a subdirectory (in the same way as the *X-Script-Name* header
|
|
is used with Nginx), and a label has been added to tell Traefik to route
|
|
requests under the subdirectory to this container.
|
|
|
|
While using the Traefik configuration for version v2 for hosting pgAdmin under subdirectory
|
|
the container is typically launched per the example below:
|
|
|
|
.. code-block:: bash
|
|
|
|
docker pull dpage/pgadmin4
|
|
docker run --name "pgadmin4" \
|
|
-e "PGADMIN_DEFAULT_EMAIL=user@domain.com" \
|
|
-e "PGADMIN_DEFAULT_PASSWORD=SuperSecret" \
|
|
-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
|
|
|
|
# Deployment manifest (spec.template.spec): pin every container that
|
|
# touches the data volume to the same explicit tag. Do NOT use :latest.
|
|
spec:
|
|
template:
|
|
spec:
|
|
initContainers:
|
|
- name: import-servers-json
|
|
image: docker.io/dpage/pgadmin4:9.14 # match the main container
|
|
# ... rest of the init container spec ...
|
|
containers:
|
|
- name: pgadmin
|
|
image: docker.io/dpage/pgadmin4:9.14 # main pgAdmin container
|
|
|
|
If you deploy pgAdmin with a Helm chart, set the equivalent image-tag values
|
|
for both the main container and every init/sidecar container rather than the
|
|
raw fields shown above. When upgrading pgAdmin, 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.
|