feat: pg with extensions and open to podmans containers
This commit is contained in:
parent
ba37edd498
commit
e7dbe470da
@ -20,6 +20,24 @@ This Ansible role installs and configures PostgreSQL for local use only. It prov
|
|||||||
Available variables with defaults (see `defaults/main.yml`):
|
Available variables with defaults (see `defaults/main.yml`):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
# PostgreSQL admin user
|
||||||
|
postgres_admin_user: postgres
|
||||||
|
|
||||||
|
# PostgreSQL admin password (REQUIRED - must be set explicitly)
|
||||||
|
# postgres_admin_password: "" # Intentionally undefined
|
||||||
|
|
||||||
|
# PostgreSQL data directory
|
||||||
|
postgres_data_dir: /var/lib/postgres/data
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
postgres_listen_addresses: 127.0.0.1 # For container access: "127.0.0.1,{{ podman_subnet_gateway }}"
|
||||||
|
postgres_port: 5432
|
||||||
|
|
||||||
|
# Firewall configuration
|
||||||
|
postgres_firewall_allowed_sources:
|
||||||
|
- 127.0.0.0/8 # Localhost
|
||||||
|
- "{{ podman_subnet | default('10.88.0.0/16') }}" # Podman bridge network
|
||||||
|
|
||||||
# Performance tuning
|
# Performance tuning
|
||||||
postgres_shared_buffers: 256MB
|
postgres_shared_buffers: 256MB
|
||||||
postgres_effective_cache_size: 1GB
|
postgres_effective_cache_size: 1GB
|
||||||
@ -75,90 +93,38 @@ Each service role (immich, nextcloud, etc.) manages its own:
|
|||||||
- Each user has a unique password
|
- Each user has a unique password
|
||||||
- Passwords stored in service role variables (use Ansible Vault for production)
|
- Passwords stored in service role variables (use Ansible Vault for production)
|
||||||
|
|
||||||
## How to Use from Service Roles
|
|
||||||
|
|
||||||
### Pattern for Service Roles
|
|
||||||
|
|
||||||
When creating a service role that needs PostgreSQL:
|
|
||||||
|
|
||||||
**1. Add postgres as a dependency** (`meta/main.yml`):
|
|
||||||
```yaml
|
|
||||||
dependencies:
|
|
||||||
- role: postgres
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Define database variables** (`defaults/main.yml`):
|
|
||||||
```yaml
|
|
||||||
myservice_db_name: myservice
|
|
||||||
myservice_db_user: myservice_user
|
|
||||||
myservice_db_password: changeme # Use Ansible Vault in production!
|
|
||||||
myservice_db_host: localhost
|
|
||||||
myservice_db_port: 5432
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Create database and user** (`tasks/main.yml`):
|
|
||||||
```yaml
|
|
||||||
- name: Create PostgreSQL database for myservice
|
|
||||||
community.postgresql.postgresql_db:
|
|
||||||
name: "{{ myservice_db_name }}"
|
|
||||||
state: present
|
|
||||||
become: true
|
|
||||||
become_user: "{{ postgres_admin_user }}"
|
|
||||||
|
|
||||||
- name: Create PostgreSQL user for myservice
|
|
||||||
community.postgresql.postgresql_user:
|
|
||||||
name: "{{ myservice_db_user }}"
|
|
||||||
password: "{{ myservice_db_password }}"
|
|
||||||
db: "{{ myservice_db_name }}"
|
|
||||||
priv: ALL
|
|
||||||
state: present
|
|
||||||
become: true
|
|
||||||
become_user: "{{ postgres_admin_user }}"
|
|
||||||
|
|
||||||
- name: Ensure user has no superuser privileges
|
|
||||||
community.postgresql.postgresql_user:
|
|
||||||
name: "{{ myservice_db_user }}"
|
|
||||||
role_attr_flags: NOSUPERUSER,NOCREATEDB,NOCREATEROLE
|
|
||||||
state: present
|
|
||||||
become: true
|
|
||||||
become_user: "{{ postgres_admin_user }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** `postgres_admin_user` is provided by the postgres role and defaults to `postgres`.
|
|
||||||
|
|
||||||
**4. Configure your service** to connect to:
|
|
||||||
```
|
|
||||||
Host: localhost
|
|
||||||
Port: 5432
|
|
||||||
Database: myservice
|
|
||||||
User: myservice_user
|
|
||||||
Password: changeme
|
|
||||||
```
|
|
||||||
|
|
||||||
### Real Example: Immich
|
|
||||||
|
|
||||||
See `roles/immich/` for a complete working example of using this pattern.
|
|
||||||
|
|
||||||
## Connection Methods
|
## Connection Methods
|
||||||
|
|
||||||
### From Containers
|
### From Containers
|
||||||
|
|
||||||
If your service runs in a container (Docker/Podman), you need to:
|
If your service runs in a container (Docker/Podman), you need to configure PostgreSQL to listen on the Podman bridge gateway:
|
||||||
|
|
||||||
**Option 1: Use host network mode**
|
**Step 1: Configure PostgreSQL in inventory**
|
||||||
```yaml
|
```yaml
|
||||||
network_mode: host
|
# inventory/host_vars/yourserver.yml
|
||||||
|
postgres_listen_addresses: "127.0.0.1,{{ podman_subnet_gateway }}"
|
||||||
|
postgres_firewall_allowed_sources:
|
||||||
|
- 127.0.0.0/8
|
||||||
|
- "{{ podman_subnet }}"
|
||||||
```
|
```
|
||||||
Then connect to `localhost:5432`
|
|
||||||
|
|
||||||
**Option 2: Use host.containers.internal (Podman/Docker)**
|
**Step 2: Use host.containers.internal in containers**
|
||||||
```yaml
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
services:
|
||||||
|
myservice:
|
||||||
|
extra_hosts:
|
||||||
|
- "host.containers.internal:host-gateway"
|
||||||
|
environment:
|
||||||
DB_HOSTNAME: host.containers.internal
|
DB_HOSTNAME: host.containers.internal
|
||||||
DB_PORT: 5432
|
DB_PORT: 5432
|
||||||
```
|
```
|
||||||
|
|
||||||
**Option 3: Bridge with firewall (less secure)**
|
**What this does:**
|
||||||
Bind postgres to `0.0.0.0` and use container gateway IP.
|
- PostgreSQL listens on `127.0.0.1` (localhost) and `10.88.0.1` (Podman gateway)
|
||||||
|
- UFW firewall allows connections from localhost and Podman subnet
|
||||||
|
- `pg_hba.conf` automatically configured to allow Podman subnet
|
||||||
|
- `host.containers.internal` resolves to the gateway IP inside containers
|
||||||
|
|
||||||
### From System Services
|
### From System Services
|
||||||
|
|
||||||
@ -198,11 +164,14 @@ The pattern above ensures users have:
|
|||||||
- ❌ Cannot create roles
|
- ❌ Cannot create roles
|
||||||
- ❌ Cannot access other databases
|
- ❌ Cannot access other databases
|
||||||
|
|
||||||
### 4. Local-Only Access
|
### 4. Controlled Access
|
||||||
|
|
||||||
PostgreSQL is configured to listen on `localhost` only:
|
PostgreSQL default configuration:
|
||||||
- No remote connections allowed
|
- Listens on `localhost` only by default
|
||||||
- Services must run on the same host
|
- To allow container access, set `postgres_listen_addresses` to include Podman gateway
|
||||||
|
- UFW firewall rules automatically configured for allowed sources
|
||||||
|
- `pg_hba.conf` automatically configured for Podman subnet when enabled
|
||||||
|
- No remote network access by default
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@ -228,7 +197,20 @@ sudo -u postgres psql
|
|||||||
|
|
||||||
### Test connection from service
|
### Test connection from service
|
||||||
```bash
|
```bash
|
||||||
|
# From localhost
|
||||||
psql -h localhost -U immich -d immich
|
psql -h localhost -U immich -d immich
|
||||||
|
|
||||||
|
# From Podman gateway (if configured)
|
||||||
|
psql -h 10.88.0.1 -U immich -d immich
|
||||||
|
|
||||||
|
# Check listen addresses
|
||||||
|
sudo -u postgres psql -c "SHOW listen_addresses;"
|
||||||
|
|
||||||
|
# Check firewall rules
|
||||||
|
sudo ufw status | grep 5432
|
||||||
|
|
||||||
|
# Check pg_hba.conf
|
||||||
|
sudo grep -v "^#" /var/lib/postgres/data/pg_hba.conf | grep -v "^$"
|
||||||
```
|
```
|
||||||
|
|
||||||
### View logs
|
### View logs
|
||||||
|
|||||||
@ -1,15 +1,25 @@
|
|||||||
---
|
---
|
||||||
# PostgreSQL admin user (used by service roles for database management)
|
# PostgreSQL port
|
||||||
|
postgres_port: 5432
|
||||||
|
|
||||||
|
# PostgreSQL admin user (only for database management)
|
||||||
postgres_admin_user: postgres
|
postgres_admin_user: postgres
|
||||||
|
|
||||||
# PostgreSQL admin password (REQUIRED - must be set explicitly)
|
# PostgreSQL admin password (REQUIRED - must be set explicitly)
|
||||||
# Set via inventory, host_vars, or ansible-vault
|
# Set via inventory, host_vars, or ansible-vault
|
||||||
# See this file's comments for setup instructions
|
# postgres_admin_password: ""
|
||||||
# postgres_admin_password: "" # Intentionally undefined - role will fail if not set
|
|
||||||
|
|
||||||
# PostgreSQL data directory
|
# PostgreSQL data directory
|
||||||
postgres_data_dir: /var/lib/postgres/data
|
postgres_data_dir: /var/lib/postgres/data
|
||||||
|
|
||||||
|
# Binding address(es)
|
||||||
|
postgres_listen_addresses: "127.0.0.1,{{ podman_subnet_gateway | default('10.88.0.1' }}"
|
||||||
|
|
||||||
|
# Firewall configuration
|
||||||
|
postgres_firewall_allowed_sources:
|
||||||
|
- 127.0.0.0/8 # Localhost
|
||||||
|
- "{{ podman_subnet | default('10.88.0.0/16') }}" # Podman bridge network
|
||||||
|
|
||||||
# Performance tuning (adjust based on your hardware)
|
# Performance tuning (adjust based on your hardware)
|
||||||
postgres_shared_buffers: 256MB
|
postgres_shared_buffers: 256MB
|
||||||
postgres_effective_cache_size: 1GB
|
postgres_effective_cache_size: 1GB
|
||||||
|
|||||||
38
roles/postgres/tasks/archlinux.yml
Normal file
38
roles/postgres/tasks/archlinux.yml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
---
|
||||||
|
- name: Check if pgvector is installed
|
||||||
|
ansible.builtin.command: pacman -Qi pgvector
|
||||||
|
register: pgvector_installed
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Install pgvector from AUR
|
||||||
|
when: pgvector_installed.rc != 0
|
||||||
|
block:
|
||||||
|
- name: Disable SUDOERS password prompt for AUR installation
|
||||||
|
no_log: true
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
dest: /etc/sudoers
|
||||||
|
state: present
|
||||||
|
regexp: "^#?%wheel"
|
||||||
|
line: "%wheel ALL=(ALL) NOPASSWD: ALL"
|
||||||
|
validate: /usr/sbin/visudo -cf %s
|
||||||
|
|
||||||
|
- name: Install pgvector from AUR
|
||||||
|
become: false
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "paru -S --noconfirm pgvector"
|
||||||
|
|
||||||
|
- name: Restore SUDOERS password prompt after AUR installation
|
||||||
|
no_log: true
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
dest: /etc/sudoers
|
||||||
|
state: present
|
||||||
|
regexp: "^#?%wheel"
|
||||||
|
line: "%wheel ALL=(ALL:ALL) ALL"
|
||||||
|
validate: /usr/sbin/visudo -cf %s
|
||||||
|
|
||||||
|
- name: Ensure PostgreSQL is initialized
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: initdb -D {{ postgres_data_dir }}
|
||||||
|
creates: "{{ postgres_data_dir }}/PG_VERSION"
|
||||||
|
become_user: "{{ postgres_admin_user }}"
|
||||||
16
roles/postgres/tasks/debian.yml
Normal file
16
roles/postgres/tasks/debian.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
- name: Create current version symlink
|
||||||
|
ansible.builtin.shell:
|
||||||
|
cmd: set -o pipefail && ln -sf $(ls -1 /etc/postgresql/ | grep -E '^[0-9]+$' | sort -V | tail -n1) /etc/postgresql/current
|
||||||
|
creates: /etc/postgresql/current
|
||||||
|
executable: /bin/bash
|
||||||
|
|
||||||
|
- name: Get installed PostgreSQL version
|
||||||
|
ansible.builtin.shell: psql --version | grep -oP '\d+' | head -1
|
||||||
|
register: postgres_version
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Install pgvector extension
|
||||||
|
ansible.builtin.package:
|
||||||
|
name: "postgresql-{{ postgres_version.stdout }}-pgvector"
|
||||||
|
state: present
|
||||||
@ -20,20 +20,8 @@
|
|||||||
name: "{{ postgres_packages }}"
|
name: "{{ postgres_packages }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Create current version symlink (Debian)
|
- name: Include OS-specific tasks
|
||||||
ansible.builtin.shell:
|
ansible.builtin.include_tasks: "{{ ansible_facts['os_family'] | lower }}.yml"
|
||||||
cmd: set -o pipefail && ln -sf $(ls -1 /etc/postgresql/ | grep -E '^[0-9]+$' | sort -V | tail -n1) /etc/postgresql/current
|
|
||||||
creates: /etc/postgresql/current
|
|
||||||
executable: /bin/bash
|
|
||||||
when: ansible_facts['os_family'] == 'Debian'
|
|
||||||
|
|
||||||
- name: Ensure PostgreSQL is initialized (Arch)
|
|
||||||
ansible.builtin.command:
|
|
||||||
cmd: initdb -D {{ postgres_data_dir }}
|
|
||||||
creates: "{{ postgres_data_dir }}/PG_VERSION"
|
|
||||||
become: true
|
|
||||||
become_user: "{{ postgres_admin_user }}"
|
|
||||||
when: ansible_facts['os_family'] == 'Archlinux'
|
|
||||||
|
|
||||||
- name: Ensure PostgreSQL config directory exists
|
- name: Ensure PostgreSQL config directory exists
|
||||||
ansible.builtin.file:
|
ansible.builtin.file:
|
||||||
@ -60,6 +48,25 @@
|
|||||||
mode: "0640"
|
mode: "0640"
|
||||||
notify: Restart PostgreSQL
|
notify: Restart PostgreSQL
|
||||||
|
|
||||||
|
- name: Configure pg_hba.conf for Podman subnet access
|
||||||
|
ansible.builtin.lineinfile:
|
||||||
|
path: "{{ postgres_hba_path }}"
|
||||||
|
line: "host all all {{ podman_subnet }} scram-sha-256"
|
||||||
|
insertafter: "^# IPv4 local connections:"
|
||||||
|
state: present
|
||||||
|
when: podman_subnet is defined
|
||||||
|
notify: Restart PostgreSQL
|
||||||
|
|
||||||
|
- name: Setup firewall rules for PostgreSQL
|
||||||
|
community.general.ufw:
|
||||||
|
rule: allow
|
||||||
|
src: "{{ item }}"
|
||||||
|
port: "{{ postgres_port }}"
|
||||||
|
proto: tcp
|
||||||
|
direction: in
|
||||||
|
comment: "PostgreSQL"
|
||||||
|
loop: "{{ postgres_firewall_allowed_sources }}"
|
||||||
|
|
||||||
- name: Enable and start PostgreSQL service
|
- name: Enable and start PostgreSQL service
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: "{{ postgres_service_name }}"
|
name: "{{ postgres_service_name }}"
|
||||||
@ -71,5 +78,4 @@
|
|||||||
name: "{{ postgres_admin_user }}"
|
name: "{{ postgres_admin_user }}"
|
||||||
password: "{{ postgres_admin_password }}"
|
password: "{{ postgres_admin_password }}"
|
||||||
state: present
|
state: present
|
||||||
become: true
|
|
||||||
become_user: "{{ postgres_admin_user }}"
|
become_user: "{{ postgres_admin_user }}"
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
# Custom PostgreSQL configuration managed by Ansible
|
# Custom PostgreSQL configuration managed by Ansible
|
||||||
# Override settings from main postgresql.conf
|
# Override settings from main postgresql.conf
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
listen_addresses = '{{ postgres_listen_addresses }}'
|
||||||
|
port = {{ postgres_port }}
|
||||||
|
|
||||||
# Performance tuning
|
# Performance tuning
|
||||||
shared_buffers = {{ postgres_shared_buffers }}
|
shared_buffers = {{ postgres_shared_buffers }}
|
||||||
effective_cache_size = {{ postgres_effective_cache_size }}
|
effective_cache_size = {{ postgres_effective_cache_size }}
|
||||||
|
|||||||
@ -3,6 +3,10 @@ postgres_packages:
|
|||||||
- postgresql
|
- postgresql
|
||||||
- python-psycopg2
|
- python-psycopg2
|
||||||
|
|
||||||
|
# AUR packages (installed via paru)
|
||||||
|
postgres_aur_packages:
|
||||||
|
- pgvector
|
||||||
|
|
||||||
postgres_service_name: postgresql
|
postgres_service_name: postgresql
|
||||||
postgres_config_path: "{{ postgres_data_dir }}/postgresql.conf"
|
postgres_config_path: "{{ postgres_data_dir }}/postgresql.conf"
|
||||||
postgres_config_dir: "{{ postgres_data_dir }}/conf.d"
|
postgres_config_dir: "{{ postgres_data_dir }}/conf.d"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user