- 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.
90 lines
4.1 KiB
Markdown
90 lines
4.1 KiB
Markdown
# images
|
|
|
|
Container images published to `containers.kritikos.io`, built with Docker Compose.
|
|
|
|
```powershell
|
|
docker compose build # all images
|
|
docker compose build postgres # one image
|
|
```
|
|
|
|
Every version is a build arg supplied from [database/.env](database/.env); see
|
|
[database/compose.yaml](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.
|