Run Postgres as a rootless Podman Quadlet, and move the 17 cluster across

Replaces the docker_container playbook, which published 5432 on 0.0.0.0 and kept
its data in /var/lib/postgresql. Postgres is now the base Quadlet unit, the same
shape as Caddy: it knows nothing about its clients, and a service attaches itself
by dropping a file into postgres.container.d/ via postgres/roles/attach. Nothing
here changes when a service is added or removed.

Pinned to 18, which is two decisions rather than one tag. Postgres 18 moved both
the image's VOLUME (/var/lib/postgresql/data -> /var/lib/postgresql) and its
default PGDATA (/var/lib/postgresql/data/pgdata -> /var/lib/postgresql/18/docker),
and the 18 entrypoint refuses to start when it finds a cluster in the old layout.
So postgres_major is the single knob: it picks the image tag and the PGDATA path
together, and the mount is now the parent directory. That also settles the
migration: a PGDATA copy cannot cross a major version, so monoco's 17.5 cluster
comes across as a pg_dumpall.

Three things that bit us and are worth keeping:

- PGDATA and its version directory are created by the role, not left to the
  container. The entrypoint runs as container-root, which under keep-id is a
  subuid on the host, and it only chowns PGDATA and its contents -- so
  ~/podman-data/postgres/18 would have been stranded subuid-owned, and the host
  user could not even rm -rf it without podman unshare.

- NetworkAlias= applies to every network the container joins, which is what a
  database hub wants, but it is one fixed value in a shared drop-in rather than
  per-service: two services writing their own would make Quadlet pass
  --network-alias twice. It is not in postgres.container itself because on a
  fresh host that unit has no Network= at all.

- The credentials live in a 0600 file read with EnvironmentFile=, not in
  Environment= lines: the unit is world-readable in ~/.config.

The play no longer uses become, and does not apply the rootless-Podman
prerequisites -- those are the shared task file at caddy/roles/podman, and the
three variables they need are duplicated at the top of vars/default.yml.

migrate-from-monoco.md records the one-time 17.5 -> 18.6 move: the dump, transfer
and restore commands, the checks that prove the restore is complete (per-database
table counts against the source), and the verified result.

The dead nginx/php-fpm templates in postgres/files/ are removed.
This commit is contained in:
tanshu committed 2026-10-16 06:52:27 +05:30
1 parent 060173db5e
commit 4297e5a71e
11 files changed
+1079 -88

No files matched your search

+28 -33
View File
@@ -1,37 +1,32 @@
#################################################
# DO Community Playbooks: Docker
#################################################
---
- hosts: all
become: true
# Deploys PostgreSQL as a rootless Podman Quadlet unit.
#
# Connects as the container user and runs everything as that user: the Quadlet
# units belong to it, so the connection's PAM session is what makes
# `systemctl --user` work without any environment juggling.
#
# gather_facts is required: podman_user and the home directory come from the
# user_id / user_dir facts.
#
# The rootless-Podman prerequisites (installing podman, enabling lingering, the
# low-port sysctl, creating the Quadlet directory) are deliberately NOT applied
# here. They are the shared task file at caddy/roles/podman/tasks/main.yaml, and
# a host that has already run caddy/playbook.yml has them:
#
# - name: Rootless Podman prerequisites
# ansible.builtin.include_tasks: "{{ playbook_dir }}/../caddy/roles/podman/tasks/main.yaml"
#
# The variables those tasks need are duplicated at the top of vars/default.yml,
# so this play stands on its own.
#
# Run with: ansible-playbook -u tanshu postgres/playbook.yml
- name: Deploy PostgreSQL as a rootless Podman Quadlet
hosts: emily
gather_facts: true
vars_files:
- vars/default.yml
tasks:
- name: Pull default Postgresql image
docker_image:
name: "{{ postgres_image }}"
source: pull
force_source: yes
- name: Ensure Nextcloud Directory exists
file:
path: "/var/lib/{{ host_directory }}"
state: directory
mode: 0755
- name: Create postgres container
docker_container:
name: "{{ postgres_name }}"
image: "{{ postgres_image }}"
state: started
restart_policy: "unless-stopped"
env:
POSTGRES_USER: "{{ pg_user }}"
POSTGRES_PASSWORD: "{{ pg_password }}"
POSTGRES_DB: 'postgres'
PGDATA: "{{ data_location }}/pgdata"
published_ports:
- 5432:5432
volumes:
- "/var/lib/{{ host_directory }}/data:{{ data_location }}"
roles:
# The base postgres unit. It does NOT know which app networks it serves.
# Each service attaches itself via postgres/roles/attach.
- postgres