playbooks/roles/vhosts/postgres/tasks/compose.yml
Haitao Pan c62386f30c fix(postgres): own PGDATA by container uid so re-runs don't break access
On re-run, "Ensure compose directories exist" reset the bind-mounted data dir
to root:root 0700. The official postgres image only chowns/initdb's an EMPTY
PGDATA, so a non-empty data dir stayed root-owned while the backend runs as uid
999 -> "could not open file global/pg_filenode.map: Permission denied" (pg_isready
still passes, masking it; ALTER USER / real queries fail).

Split the dir task: compose project dir stays root:root; data dir is created
owned by postgresql_container_uid/gid (default 999), idempotent across re-runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 22:42:11 +08:00

116 lines
3.8 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
- name: Inspect Docker runtime for PostgreSQL compose mode
ansible.builtin.command: docker --version
register: postgresql_docker_version
changed_when: false
failed_when: false
- name: Ensure Docker runtime is installed for PostgreSQL compose mode
ansible.builtin.include_role:
name: roles/vhosts/docker
when: postgresql_docker_version.rc != 0
- name: Materialize PostgreSQL admin password
ansible.builtin.assert:
that:
- postgresql_admin_password | length > 0
fail_msg: "PostgreSQL admin password must not be empty."
no_log: true
- name: Inspect persisted PostgreSQL admin password
ansible.builtin.stat:
path: "{{ postgresql_admin_password_file }}"
register: postgresql_admin_password_file_status
no_log: true
- name: Protect persisted PostgreSQL admin password
ansible.builtin.file:
path: "{{ postgresql_admin_password_file }}"
owner: root
group: root
mode: "0600"
state: file
no_log: true
when: postgresql_admin_password_file_status.stat.exists
- name: Ensure PostgreSQL compose project directory exists
ansible.builtin.file:
path: "{{ postgresql_compose_project_dir }}"
state: directory
owner: root
group: root
mode: "0755"
# 数据目录归容器内 postgres uid默认 999而非 root否则重跑时这个 file
# 任务会把 PGDATA 顶层重置回 root:root 0700而非空 PGDATA 不再被 entrypoint
# chown导致 uid 999 无法进入 → "could not open file ... Permission denied"。
- name: Ensure PostgreSQL data directory exists (owned by container postgres uid)
ansible.builtin.file:
path: "{{ postgresql_data_dir }}"
state: directory
owner: "{{ postgresql_container_uid }}"
group: "{{ postgresql_container_gid }}"
mode: "0700"
- name: Render PostgreSQL compose environment
ansible.builtin.copy:
dest: "{{ postgresql_compose_env_file }}"
owner: root
group: root
mode: "0600"
content: |
POSTGRES_DB={{ postgresql_database }}
POSTGRES_USER={{ postgresql_admin_user }}
POSTGRES_PASSWORD={{ postgresql_admin_password }}
no_log: true
- name: Render PostgreSQL compose file
ansible.builtin.template:
src: postgres-compose.yml.j2
dest: "{{ postgresql_compose_file }}"
owner: root
group: root
mode: "0644"
- name: Validate PostgreSQL compose file
ansible.builtin.command:
cmd: "docker compose -f {{ postgresql_compose_file }} config --quiet"
chdir: "{{ postgresql_compose_project_dir }}"
changed_when: false
- name: Start PostgreSQL compose service
ansible.builtin.command:
cmd: "docker compose -f {{ postgresql_compose_file }} -p {{ postgresql_compose_project_name }} up -d --remove-orphans"
chdir: "{{ postgresql_compose_project_dir }}"
register: postgresql_compose_up
changed_when: >-
'Started' in (postgresql_compose_up.stdout | default('')) or
'Created' in (postgresql_compose_up.stdout | default('')) or
'Recreated' in (postgresql_compose_up.stdout | default('')) or
'Pulled' in (postgresql_compose_up.stdout | default(''))
- name: Validate PostgreSQL compose service
ansible.builtin.command:
cmd: "docker exec {{ postgresql_container_name }} pg_isready -U {{ postgresql_admin_user }} -d {{ postgresql_database }}"
register: postgresql_compose_ready
retries: 12
delay: 5
until: postgresql_compose_ready.rc == 0
changed_when: false
when: not ansible_check_mode
- name: Synchronize PostgreSQL admin password
ansible.builtin.command:
argv:
- docker
- exec
- "{{ postgresql_container_name }}"
- psql
- -U
- "{{ postgresql_admin_user }}"
- -c
- "ALTER USER {{ postgresql_admin_user }} WITH PASSWORD '{{ postgresql_admin_password | replace(\"'\", \"''\") }}';"
changed_when: false
no_log: true
when: not ansible_check_mode