Files
container-images/README.md
T
akritikos 5744f4b7db ✨ Commits existing images to git
- Implemented sync-roles.sh to synchronize Active Directory group memberships as MariaDB roles and user accounts.
- Created Containerfile for building a custom ldap2pg image with patched YAML decoding.
- Added provision-user-db.sh for provisioning user databases and roles based on LDAP synchronization.
- Introduced a new Containerfile for MariaDB with PAM authentication via pam_ldap.
- Configured PAM service for MariaDB logins and added necessary plugins for LDAP authentication.
- Implemented health checks and entrypoint scripts for MariaDB and pgpool containers.
- Enhanced PostgreSQL image with additional extensions and custom pg_hba.conf for improved security and functionality.
2026-08-15 19:57:25 +03:00

4.1 KiB

images

Container images published to containers.kritikos.io, built with Docker Compose.

docker compose build          # all images
docker compose build postgres # one image

Every version is a build arg supplied from database/.env; see database/compose.yaml for the wiring.

Alpine version vs. PostgreSQL major

ALPINE_VERSION and PG_MAJOR are not independent. The Alpine-based images (pgpool, ldap2pg, ldap2mariadb) install PostgreSQL packages with apk add postgresql${PG_MAJOR}-dev / -client, and an Alpine image's apk repositories are fixed to that release's branch. Each branch packages only a subset of PostgreSQL majors, and that subset changes every release:

Alpine branch postgresql*-dev available
edge 18, 17, 16
v3.24 18, 17 (main), 16 (community)
v3.23 18, 17 (main), 16 (community)
v3.22 17, 16 (main), 15 (community)

Measured with apk policy inside each branch's image on 2026-08-15.

So PG_MAJOR=18 requires Alpine 3.23 or newer. The coupling breaks in both directions:

  • Raising PG_MAJOR before Alpine's stable branch packages that major fails the build — a September PostgreSQL release will not reach a stable Alpine until that branch ships.
  • Leaving PG_MAJOR behind while Alpine advances fails eventually too: ageing majors are demoted from main to community, then dropped. 16 has already fallen to community on v3.23, and 15 is gone from v3.23 onwards.

Bump ALPINE_VERSION and PG_MAJOR together, and confirm the target branch carries postgresql${PG_MAJOR}-dev before doing so.

Pinning matters because alpine:latest is a mutable tag that follows Alpine's roughly six-monthly releases, so the same commit can build against a different base OS and a different package set on a later day. Note that --no-cache on apk add does not pin anything — it only avoids a stale index, and package versions still float within the branch.

pgpool is the image most exposed to this, since it is the one that compiles against postgresql${PG_MAJOR}-dev rather than just installing a client. All three Alpine-based images (pgpool, ldap2pg, ldap2mariadb) take ALPINE_VERSION from database/.env, currently pinned to 3.23.

pgpool health check

pgpool ships no health endpoint of its own. Its health_check_period settings govern how pgpool probes its backends to drive failover, and the PCP tools (pcp_node_info and friends) need a pcp.conf user plus a password file, which is more than a container probe should carry. The image therefore probes with pg_isready against the pgpool port.

What that reports, measured against two live backends:

Backend state Health
all nodes up green
standby down, degenerated green
primary down, standby promoted green
during failover (~one check cycle) red
no node attached, or no primary red

So green means pgpool can serve, not that the cluster is healthy. Losing a standby is invisible to it, and because pgpool keeps a node down until pcp_attach_node is run, the probe stays green after a backend recovers while the pool is still running on one node. Track node-level state with SHOW POOL_NODES instead.

Two consequences for compose files consuming this image:

  • depends_on: condition: service_healthy is the intended use — it stops dependents from starting against a pool that has no primary.
  • Do not restart pgpool on unhealthy. Bouncing it during a backend outage resets its node status and drops the pool without fixing anything.

In a real streaming-replication cluster the survivor of a primary loss is in recovery, so find_primary_node reports nothing until failover_command promotes it; connections fail with failed to create a backend connection and the probe goes red for that whole window. The check is therefore gated on failover automation working, not merely on a node being up.