v1.0
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
secrets.yml
|
||||||
|
inventory.ini
|
||||||
160
INSTALL.md
Normal file
160
INSTALL.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# PostgreSQL Production Deployment Guide via Ansible
|
||||||
|
|
||||||
|
## 1. Instalacja serwerów
|
||||||
|
|
||||||
|
Dwa serwery Debian 12:
|
||||||
|
|
||||||
|
| Serwer | Rola | IP |
|
||||||
|
| ------ | ------- | -------- |
|
||||||
|
| pg-1 | Primary | 10.0.0.1 |
|
||||||
|
| pg-2 | Replica | 10.0.0.2 |
|
||||||
|
|
||||||
|
Na każdym serwerze wykonaj:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt upgrade -y
|
||||||
|
sudo apt install -y sudo vim curl gnupg rsync unzip
|
||||||
|
```
|
||||||
|
|
||||||
|
Opcjonalnie utwórz konto do Ansible:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo adduser ansible
|
||||||
|
sudo usermod -aG sudo ansible
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Konfiguracja IP i DNS
|
||||||
|
|
||||||
|
Edytuj `/etc/hosts` na obu serwerach:
|
||||||
|
|
||||||
|
**pg-1 (/etc/hosts)**
|
||||||
|
|
||||||
|
```
|
||||||
|
10.0.0.1 pg1
|
||||||
|
10.0.0.2 pg2
|
||||||
|
```
|
||||||
|
|
||||||
|
**pg-2 (/etc/hosts)**
|
||||||
|
|
||||||
|
```
|
||||||
|
10.0.0.1 pg1
|
||||||
|
10.0.0.2 pg2
|
||||||
|
```
|
||||||
|
|
||||||
|
Upewnij się, że hostnames `pg1` i `pg2` są rozpoznawane w sieci.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Przygotowanie repozytorium Ansible na pg-1
|
||||||
|
|
||||||
|
Skopiuj paczkę Ansible na pg-1:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp postgres_ansible_prod_full.zip user@pg-1:/home/user/
|
||||||
|
ssh pg-1
|
||||||
|
unzip postgres_ansible_prod_full.zip -d ~/postgres_ansible_prod
|
||||||
|
cd ~/postgres_ansible_prod
|
||||||
|
```
|
||||||
|
|
||||||
|
Edytuj `inventory.ini`, jeśli IP lub hostnames są inne:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[primary]
|
||||||
|
pg1 ansible_host=10.0.0.1
|
||||||
|
|
||||||
|
[replica]
|
||||||
|
pg2 ansible_host=10.0.0.2
|
||||||
|
|
||||||
|
[all:vars]
|
||||||
|
ansible_user=root
|
||||||
|
pg_version=16
|
||||||
|
pg_cluster=main
|
||||||
|
pg_data=/var/lib/postgresql/16/main
|
||||||
|
```
|
||||||
|
|
||||||
|
Ustaw hasła w `group_vars/all/secrets.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
replicator_password: "SILNE_HASLO_REPL"
|
||||||
|
mailuser_password: "SILNE_HASLO_DB"
|
||||||
|
```
|
||||||
|
|
||||||
|
Opcjonalnie zaszyfruj je Ansible Vault:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-vault encrypt group_vars/all/secrets.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Uruchomienie playbooka
|
||||||
|
|
||||||
|
Zainstaluj Ansible na pg-1:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install -y ansible
|
||||||
|
ansible --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Test połączenia z pg-2:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible -i inventory.ini all -m ping
|
||||||
|
```
|
||||||
|
|
||||||
|
Uruchomienie wdrożenia:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory.ini site.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Playbook automatycznie:
|
||||||
|
|
||||||
|
- Instaluje PostgreSQL 16 na obu serwerach
|
||||||
|
- Konfiguruje primary i replica
|
||||||
|
- Tworzy użytkownika `mailuser` i bazę `mailarchiver`
|
||||||
|
- Ustawia pgBackRest i cron backupów (full i incremental)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Test działania
|
||||||
|
|
||||||
|
Na pg-1:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u postgres psql -c "\l"
|
||||||
|
sudo -u postgres psql -c "\du"
|
||||||
|
```
|
||||||
|
|
||||||
|
Sprawdź replikację:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;"
|
||||||
|
```
|
||||||
|
|
||||||
|
Test backupów (pgBackRest):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u postgres pgbackrest --stanza=main info
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Przywracanie w razie awarii
|
||||||
|
|
||||||
|
Jeśli pg-1 padnie, przywracasz z pg-2:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory.ini restore_primary.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Ręczny failover (promowanie pg-2 na primary):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u postgres pg_ctl promote
|
||||||
|
```
|
||||||
|
|
||||||
|
Następnie zmień DNS lub connection string w aplikacji, aby wskazywał nowy primary.
|
||||||
59
README.md
Normal file
59
README.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# README.md
|
||||||
|
|
||||||
|
# PostgreSQL Production Setup via Ansible
|
||||||
|
|
||||||
|
Kompletne wdrożenie PostgreSQL 16 z repliką, backupami, PITR i bazą MailArchiver.
|
||||||
|
|
||||||
|
## Struktura repo
|
||||||
|
|
||||||
|
```
|
||||||
|
ansible/
|
||||||
|
├── inventory.ini
|
||||||
|
├── site.yml
|
||||||
|
├── group_vars/all/secrets.yml
|
||||||
|
└── roles/
|
||||||
|
├── common/
|
||||||
|
│ └── tasks/main.yml
|
||||||
|
├── postgres/
|
||||||
|
│ ├── tasks/main.yml
|
||||||
|
│ └── templates/
|
||||||
|
│ ├── postgresql.conf.j2
|
||||||
|
│ └── pg_hba.conf.j2
|
||||||
|
├── replication/
|
||||||
|
│ └── tasks/main.yml
|
||||||
|
├── pgbackrest/
|
||||||
|
│ ├── tasks/main.yml
|
||||||
|
│ └── templates/pgbackrest.conf.j2
|
||||||
|
└── mailarchiver_db/
|
||||||
|
└── tasks/main.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Instalacja i konfiguracja
|
||||||
|
|
||||||
|
[INSTALL.md](INSTALL.md)
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
|
||||||
|
- Full backup: niedziela 2:00
|
||||||
|
- Incremental backup: codziennie 2:00
|
||||||
|
- WAL archiving dla PITR
|
||||||
|
|
||||||
|
## Failover ręczny
|
||||||
|
|
||||||
|
Na pg2:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u postgres pg_ctl promote
|
||||||
|
```
|
||||||
|
|
||||||
|
Następnie zmień aplikację, aby łączyła się z nowym primary.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Uwagi produkcyjne
|
||||||
|
|
||||||
|
- Aplikacja musi łączyć się tylko z primary
|
||||||
|
- Repozytorium backupu na pg2
|
||||||
|
- Monitoruj `/pgbackrest` i WAL
|
||||||
|
- Wersja z Ansible Vault chroni hasła
|
||||||
|
- Test restore co tydzień zalecany
|
||||||
2
group_vars/all/secrets.yml.example
Normal file
2
group_vars/all/secrets.yml.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
replicator_password: "SILNE_HASLO_REPL"
|
||||||
|
mailuser_password: "SILNE_HASLO_DB"
|
||||||
11
inventory.ini.example
Normal file
11
inventory.ini.example
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[primary]
|
||||||
|
pg1 ansible_host=10.0.0.1
|
||||||
|
|
||||||
|
[replica]
|
||||||
|
pg2 ansible_host=10.0.0.2
|
||||||
|
|
||||||
|
[all:vars]
|
||||||
|
ansible_user=root
|
||||||
|
pg_version=16
|
||||||
|
pg_cluster=main
|
||||||
|
pg_data=/var/lib/postgresql/16/main
|
||||||
8
roles/common/tasks/main.yml
Normal file
8
roles/common/tasks/main.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
- name: Basic packages
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- vim
|
||||||
|
- curl
|
||||||
|
- gnupg
|
||||||
|
- rsync
|
||||||
|
update_cache: yes
|
||||||
20
roles/mailarchiver_db/tasks/main.yml
Normal file
20
roles/mailarchiver_db/tasks/main.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
- name: Create db user
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_user:
|
||||||
|
name: mailuser
|
||||||
|
password: "{{ mailuser_password }}"
|
||||||
|
|
||||||
|
- name: Create database
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_db:
|
||||||
|
name: mailarchiver
|
||||||
|
owner: mailuser
|
||||||
|
|
||||||
|
- name: Grant schema rights
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_query:
|
||||||
|
db: mailarchiver
|
||||||
|
query: |
|
||||||
|
GRANT ALL ON SCHEMA public TO mailuser;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||||
|
GRANT ALL ON TABLES TO mailuser;
|
||||||
37
roles/pgbackrest/tasks/main.yml
Normal file
37
roles/pgbackrest/tasks/main.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
- name: Install pgBackRest
|
||||||
|
apt:
|
||||||
|
name: pgbackrest
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Repo dir
|
||||||
|
file:
|
||||||
|
path: /pgbackrest
|
||||||
|
state: directory
|
||||||
|
owner: postgres
|
||||||
|
mode: "750"
|
||||||
|
when: inventory_hostname in groups['replica']
|
||||||
|
|
||||||
|
- name: Config
|
||||||
|
template:
|
||||||
|
src: pgbackrest.conf.j2
|
||||||
|
dest: /etc/pgbackrest.conf
|
||||||
|
|
||||||
|
- name: Create stanza
|
||||||
|
become_user: postgres
|
||||||
|
command: pgbackrest --stanza=main stanza-create
|
||||||
|
when: inventory_hostname in groups['primary']
|
||||||
|
|
||||||
|
- name: Full backup weekly
|
||||||
|
cron:
|
||||||
|
name: "pgbackrest full"
|
||||||
|
weekday: 0
|
||||||
|
hour: 2
|
||||||
|
minute: 0
|
||||||
|
job: "pgbackrest --stanza=main backup --type=full"
|
||||||
|
|
||||||
|
- name: Incremental backup daily
|
||||||
|
cron:
|
||||||
|
name: "pgbackrest incr"
|
||||||
|
hour: 2
|
||||||
|
minute: 0
|
||||||
|
job: "pgbackrest --stanza=main backup --type=incr"
|
||||||
11
roles/pgbackrest/templates/pgbackrest.conf.j2
Normal file
11
roles/pgbackrest/templates/pgbackrest.conf.j2
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[main]
|
||||||
|
pg1-path=/var/lib/postgresql/16/main
|
||||||
|
|
||||||
|
[global]
|
||||||
|
{% if inventory_hostname in groups['primary'] %}
|
||||||
|
repo1-host=pg2
|
||||||
|
{% endif %}
|
||||||
|
repo1-path=/pgbackrest
|
||||||
|
repo1-retention-full=2
|
||||||
|
repo1-retention-diff=7
|
||||||
|
start-fast=y
|
||||||
47
roles/postgres/tasks/main.yml
Normal file
47
roles/postgres/tasks/main.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
- name: Install PostgreSQL
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- postgresql-{{ pg_version }}
|
||||||
|
- postgresql-contrib
|
||||||
|
update_cache: yes
|
||||||
|
|
||||||
|
- name: Stop postgres before config
|
||||||
|
service:
|
||||||
|
name: postgresql
|
||||||
|
state: stopped
|
||||||
|
|
||||||
|
- name: postgresql.conf
|
||||||
|
template:
|
||||||
|
src: postgresql.conf.j2
|
||||||
|
dest: /etc/postgresql/{{ pg_version }}/main/postgresql.conf
|
||||||
|
|
||||||
|
- name: pg_hba.conf
|
||||||
|
template:
|
||||||
|
src: pg_hba.conf.j2
|
||||||
|
dest: /etc/postgresql/{{ pg_version }}/main/pg_hba.conf
|
||||||
|
|
||||||
|
- name: TLS cert dir
|
||||||
|
file:
|
||||||
|
path: /etc/postgresql/ssl
|
||||||
|
state: directory
|
||||||
|
owner: postgres
|
||||||
|
mode: "700"
|
||||||
|
|
||||||
|
- name: Copy TLS cert
|
||||||
|
copy:
|
||||||
|
src: pg.crt
|
||||||
|
dest: /etc/postgresql/ssl/pg.crt
|
||||||
|
owner: postgres
|
||||||
|
mode: "600"
|
||||||
|
|
||||||
|
- name: Copy TLS key
|
||||||
|
copy:
|
||||||
|
src: pg.key
|
||||||
|
dest: /etc/postgresql/ssl/pg.key
|
||||||
|
owner: postgres
|
||||||
|
mode: "600"
|
||||||
|
|
||||||
|
- name: Start postgres
|
||||||
|
service:
|
||||||
|
name: postgresql
|
||||||
|
state: started
|
||||||
3
roles/postgres/tasks/templates/pg_hba.conf.j2
Normal file
3
roles/postgres/tasks/templates/pg_hba.conf.j2
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
local all postgres peer
|
||||||
|
host all all 10.0.0.0/24 md5
|
||||||
|
host replication replicator 10.0.0.2/32 md5
|
||||||
13
roles/postgres/tasks/templates/postgresql.conf.j2
Normal file
13
roles/postgres/tasks/templates/postgresql.conf.j2
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
listen_addresses = '*'
|
||||||
|
|
||||||
|
shared_buffers = 2GB
|
||||||
|
effective_cache_size = 6GB
|
||||||
|
work_mem = 64MB
|
||||||
|
maintenance_work_mem = 1GB
|
||||||
|
|
||||||
|
wal_compression = on
|
||||||
|
checkpoint_timeout = 15min
|
||||||
|
max_wal_size = 64GB
|
||||||
|
|
||||||
|
archive_mode = on
|
||||||
|
archive_command = 'pgbackrest --stanza=main archive-push %p'
|
||||||
28
roles/replication/tasks/main.yml
Normal file
28
roles/replication/tasks/main.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
- name: Create replicator user (on primary)
|
||||||
|
delegate_to: pg1
|
||||||
|
become_user: postgres
|
||||||
|
postgresql_user:
|
||||||
|
name: replicator
|
||||||
|
password: "{{ replicator_password }}"
|
||||||
|
role_attr_flags: REPLICATION,LOGIN
|
||||||
|
|
||||||
|
- name: Stop postgres
|
||||||
|
service:
|
||||||
|
name: postgresql
|
||||||
|
state: stopped
|
||||||
|
|
||||||
|
- name: Remove old data
|
||||||
|
file:
|
||||||
|
path: "{{ pg_data }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Base backup
|
||||||
|
become_user: postgres
|
||||||
|
command: >
|
||||||
|
pg_basebackup -h pg1 -D {{ pg_data }}
|
||||||
|
-U replicator -Fp -Xs -P -R
|
||||||
|
|
||||||
|
- name: Start postgres
|
||||||
|
service:
|
||||||
|
name: postgresql
|
||||||
|
state: started
|
||||||
19
roles/restore_primary/tasks/main.yml
Normal file
19
roles/restore_primary/tasks/main.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
- name: Stop postgres on primary
|
||||||
|
service:
|
||||||
|
name: postgresql
|
||||||
|
state: stopped
|
||||||
|
|
||||||
|
- name: Remove old data on primary
|
||||||
|
file:
|
||||||
|
path: "{{ pg_data }}"
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Restore base backup from replica
|
||||||
|
become_user: postgres
|
||||||
|
command: >
|
||||||
|
pg_basebackup -h pg2 -D {{ pg_data }} -U replicator -Fp -Xs -P -R
|
||||||
|
|
||||||
|
- name: Start postgres on primary
|
||||||
|
service:
|
||||||
|
name: postgresql
|
||||||
|
state: started
|
||||||
Reference in New Issue
Block a user