Files
ROMFASTSQL/proxmox/cluster/docs/oprire-planificata-cluster.md
Marius 730ce94fac feat(cluster): varianta PowerShell a scripturilor de oprire/repornire
Statia de admin e Windows si nu ruleaza .sh direct: `bash` din PATH e cel din
WSL, cu alt filesystem si alta configuratie de chei SSH. Adaug echivalentele
native PowerShell.

- cluster-shutdown.ps1 / cluster-startup.ps1, aceeasi logica si aceleasi
  garantii ca variantele bash
- folosesc clientul OpenSSH din Windows, deja prezent in System32
- compatibile PowerShell 5.1: fara &&/||, fara ternar, fara ?., fara
  -AsHashtable; ping prin System.Net.NetworkInformation.Ping, nu
  Test-Connection (WMI, lent si des blocat)
- nu redirecteaza stderr-ul lui ssh: in 5.1 asta transforma fiecare linie
  intr-un ErrorRecord si strica $LASTEXITCODE chiar cand comanda a reusit
- parsarea `pct list` / `qm list` se face in PowerShell, nu prin awk remote,
  ca sa nu se incurce interpolarea $1/$2 din stringurile PowerShell
- scriu acelasi format de fisier de stare ca variantele bash, deci poti opri
  cu una si porni cu cealalta

Ambele testate cu -DryRun pe clusterul live, rezultat identic cu bash.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRyaDj39hPQ89SZS6URRpS
2026-08-27 14:04:50 +03:00

362 lines
13 KiB
Markdown

# Oprire planificată a clusterului (lucrări la rețeaua electrică)
Procedura de oprire controlată a tuturor celor 3 noduri Proxmox **fără ca HA să
relocheze resursele** și **fără ca watchdog-ul să reseteze hard vreun nod**.
Se aplică oricărei opriri planificate a întregului cluster: lucrări electrice,
mutare rack, mentenanță UPS, intervenții la switch.
**Autor:** Claude Code · **Ultima verificare pe cluster live:** 2026-08-27
---
## Varianta automată
Toată procedura de mai jos e implementată în două scripturi, de rulat **de pe
stația de admin** (nu de pe un nod). Există în două variante echivalente —
folosește-o pe cea potrivită shell-ului tău.
**PowerShell (Windows, varianta obișnuită aici):**
```powershell
cd E:\proiecte\ROMFASTSQL\proxmox\cluster\scripts
.\cluster-shutdown.ps1 -DryRun # arată exact ce ar face, nu atinge nimic
.\cluster-shutdown.ps1 # oprire completă, cu confirmări
# ... după revenirea curentului, cu nodurile pornite fizic ...
.\cluster-startup.ps1 # repornire completă
```
Cere doar clientul OpenSSH din Windows (`C:\Windows\System32\OpenSSH\ssh.exe`),
deja prezent, și cheia SSH pentru root pe noduri. Testate pe PowerShell 5.1.
Dacă politica de execuție blochează scriptul:
`powershell -ExecutionPolicy Bypass -File .\cluster-shutdown.ps1 -DryRun`
**Bash (Git Bash, WSL sau de pe CT 171 claude-agent):**
```bash
cd proxmox/cluster/scripts
./cluster-shutdown.sh --dry-run
./cluster-shutdown.sh
./cluster-startup.sh
```
Cele două variante scriu același fișier de stare, deci poți opri cu una și porni
cu cealaltă.
`cluster-shutdown.sh` salvează local ce guest-uri rulau, iar `cluster-startup.sh`
pornește **exact** ce era pornit — nu repornește VM-uri oprite intenționat.
**Rulează întâi cu `--dry-run`.** Restul documentului explică de ce fiecare pas e
necesar și cum se face manual din GUI, dacă preferi.
---
## TL;DR (procedura manuală)
1. **Datacenter → Options → HA Settings → Shutdown Policy = `Freeze`** ← fără asta, HA mută resursele
2. Dezactivează cron-urile de alertă (`pvemini-down-alert`, `vm109-watchdog`, `pveelite-down-alert`, `oom-alert`)
3. Oprește guest-urile manual — **Oracle CT 108 primul**, cu `shutdown immediate` în DB
4. `ha-manager status` → toate serviciile trebuie să fie `stopped`
5. Oprește nodurile: **pveelite → pve1 → pvemini**
La revenire: pornești **toate trei nodurile aproape simultan** (altfel nu ai quorum).
---
## De ce nu poți pur și simplu să apeși „Shutdown"
### Capcana 1 — politica implicită de shutdown este `conditional`
Pe clusterul `romfast` **nu există** `/etc/pve/datacenter.cfg`, deci PVE folosește
default-ul `shutdown_policy=conditional`:
| Acțiune pe nod | Comportament HA cu `conditional` |
|----------------|----------------------------------|
| **Reboot** | freeze — serviciile rămân pe nod |
| **Shutdown (poweroff)** | **failover** — serviciile se relochează pe alt nod |
Adică exact ce vrei să eviți: un „Shutdown" pe pvemini trimite CT 108 Oracle,
VM 201 și restul resurselor HA pe pve1/pveelite — pe noduri care oricum urmează
să fie și ele oprite, cu 16 GB RAM pe pveelite și riscul din
[incidentul 2026-04-20](../incidents/2026-04-20-cluster-outage.md).
### Capcana 2 — watchdog-ul se auto-fence la pierderea quorumului
Cu 3 noduri, quorum = 2. Dacă oprești două noduri și al treilea **încă are
servicii HA active**, LRM-ul pierde agent lock-ul și watchdog-ul face **reset
hard** după ~60 s. Nu shutdown curat — reset brutal, peste Oracle pornit.
Soluția e la Pasul 3: cu toate resursele HA în state `stopped`, LRM-ul nu mai
are nimic activ, **watchdog-ul nu mai e armat**, iar pierderea quorumului devine
inofensivă.
### Ce să NU faci
- ❌ **Nu folosi node maintenance mode** (`ha-manager crm-command node-maintenance
enable <nod>`) — acela migrează *intenționat* resursele, exact opusul scopului.
- ❌ **Nu opri două noduri și nu lăsa unul pornit cu servicii HA active** — vezi capcana 2.
- ❌ **Nu lăsa nodul să oprească el guest-urile** — Oracle și Windows au nevoie de
shutdown curat, nu de timeout.
---
## Pas 0 — Shutdown Policy = Freeze
**GUI:** `Datacenter → Options → HA Settings → Edit → Shutdown Policy: Freeze`
**CLI (echivalent):**
```bash
ssh root@10.0.20.201 "echo 'ha: shutdown_policy=freeze' >> /etc/pve/datacenter.cfg"
```
`Freeze` = la oprirea nodului serviciile HA sunt înghețate, **nu relocate**;
repornesc pe același nod când nodul revine.
> **Recomandare permanentă:** lasă `freeze` și după intervenție. Docul de failover
> descrie deja un incident în care VM 201 a migrat nedorit în timpul unei
> mentenanțe — `freeze` e politica potrivită pentru acest cluster.
---
## Pas 1 — dezactivează alertele automate
Altfel primești zeci de mailuri, iar `vm109-watchdog.sh` conține un `qm start 109`
care poate porni VM 109 fix când nu trebuie.
Ce trebuie dezactivat pe fiecare nod:
| Nod | Script | De ce |
|-----|--------|-------|
| pveelite | `pvemini-down-alert.sh` | mail la fiecare minut cât pvemini e jos |
| pveelite | `vm109-watchdog.sh` | conține `qm start 109` |
| pveelite | `oom-alert.sh` | zgomot |
| **pvemini** | **`vm109-watchdog.sh`** | **rulează și aici, nu doar pe pveelite** |
| pvemini | `pveelite-down-alert.sh` | zgomot |
| pvemini | `oom-alert.sh` | zgomot |
| pve1 | `oom-alert.sh` | zgomot |
Comandă unică, rulată pe fiecare nod — face backup și comentează exact liniile
astea, lăsând restul crontab-ului neatins:
```bash
for h in 10.0.20.200 10.0.20.201 10.0.20.202; do
ssh root@$h 'crontab -l > /root/crontab.backup-mentenanta.txt; \
crontab -l | sed -E "/^[^#]/ s%^(.*(oom-alert|pvemini-down-alert|pveelite-down-alert|vm109-watchdog)\.sh.*)$%#MENTENANTA \1%" | crontab -'
done
```
Restaurare după intervenție:
```bash
for h in 10.0.20.200 10.0.20.201 10.0.20.202; do
ssh root@$h 'crontab /root/crontab.backup-mentenanta.txt && crontab -l | grep -c MENTENANTA'
done # trebuie sa intoarca 0 pe fiecare nod
```
> `pvemini-down-alert.sh` doar **trimite mail** cu comanda de failover, nu o
> execută singur — verificat în cod. `vm109-watchdog.sh` însă chiar pornește VM 109,
> și rulează pe **ambele** noduri (pvemini și pveelite).
### ⚠️ Dacă fereastra de lucrări prinde sâmbătă dimineața
`weekly-dr-test-proxmox.sh` rulează **sâmbătă la 06:00, pe pvemini ȘI pe pveelite**,
și **pornește VM 109**. Conform [incidentului 2026-04-20](../incidents/2026-04-20-cluster-outage.md),
scriptul are istoric de a lăsa VM 109 pornit după un eșec (bug `set -e`) — exact
declanșatorul buclei OOM de atunci.
Dacă intervenția atinge sâmbătă 06:00, comentează-l pe ambele noduri.
La fel `vm109-patch-window.sh` (zilele 1-7 ale lunii, ora 03:00) dacă fereastra
prinde începutul de lună.
### Job-uri de backup
Verifică dacă fereastra de lucrări prinde un job vzdump. Dacă da, dezactivează-l
din `Datacenter → Backup` înainte:
| Job | Program |
|-----|---------|
| `backup-impare-oracle` (CT 108) | zile impare 02:00 |
| `backup-impare-rest` (100, 103, 106, 171) | zile impare 03:00 |
| `backup-pare-flowise` (CT 104) | zile pare 02:00 |
| `backup-pare-windows` (VM 201) | zile pare 03:30 |
| `backup-pve1-minecraft` (CT 101) | zile impare 22:00 |
| `backup-f1c87584` (VM 109) | sâmbătă 15:00, prima săptămână |
Replicarea ZFS (`pvesr`) nu trebuie dezactivată — job-urile ratate se recuperează
singure la primul tick după revenire.
---
## Pas 2 — oprește guest-urile manual
Ordinea corectă e cea de **dependențe: consumatorii întâi, Oracle ULTIMUL**.
VM 201 (IIS) și CT 104 (flowise) folosesc baza din CT 108.
| # | Nod | Guest | În HA | Cum |
|---|-----|-------|-------|-----|
| 1 | pvemini | VM 303 Win11-Adina | Nu | Shutdown |
| 2 | pvemini | VM 302 oracle-test | Nu | Shutdown |
| 3 | pvemini | VM 201 roacentral | Da | Shutdown (guest agent) |
| 4 | pve1 | CT 101 minecraft | Da | Shutdown |
| 5 | pve1 | CT 110 moltbot | Da | Shutdown |
| 6 | pvemini | CT 104 flowise | Da | Shutdown |
| 7 | pvemini | CT 106 gitea | Da | Shutdown |
| 8 | pvemini | CT 103 dokploy | Da | Shutdown |
| 9 | pvemini | CT 102 docker.romfast.ro | Nu | Shutdown |
| 10 | pvemini | CT 100 portainer | Da | Shutdown |
| 11 | pvemini | CT 171 claude-agent | Da | Shutdown |
| 12 | pvemini | **CT 108 central-oracle** | Da | `shutdown immediate` în DB, apoi Shutdown CT |
pveelite nu are nimic pornit în mod normal (CT 301 și VM 109 sunt `stopped`).
> **Din CLI, folosește `ha-manager set <sid> --state stopped` pentru guest-urile
> din HA**, nu `pct shutdown` / `qm shutdown`. Din linia de comandă acestea **nu**
> actualizează state-ul HA, iar CRM-ul poate reporni guest-ul în mijlocul opririi.
> Din GUI nu e o problemă — butonul Shutdown trece oricum prin HA.
### Oracle CT 108 — shutdown curat al bazei
```bash
ssh root@10.0.20.201 "pct exec 108 -- docker exec oracle-xe bash -lc \
\"printf 'shutdown immediate\nexit\n' | sqlplus -s / as sysdba\""
```
Abia după ce comanda întoarce `Database closed / Database dismounted / ORACLE
instance shut down`, oprești containerul din GUI.
### Restul
După ce Oracle e jos, poți folosi **Bulk Actions → Bulk Shutdown** pe fiecare nod.
> Oprirea unui guest HA din GUI îi setează automat state-ul HA pe `stopped` — CRM-ul
> nu îl va reporni. **Consecință:** la revenire trebuie să le pornești tu manual
> (pornirea îi pune state-ul înapoi pe `started`).
---
## Pas 3 — verificare obligatorie înainte de oprirea nodurilor
```bash
ssh root@10.0.20.201 "ha-manager status"
```
**Toate** liniile `service ...` trebuie să arate `(nod, stopped)`.
Dacă vreuna arată `started`, `migrate`, `relocate` sau `fence` — **oprește-te**.
Nu opri niciun nod până nu se stabilizează, altfel intri fix în scenariul de la
capcana 2.
Verificare rapidă că nu a mai rămas nimic pornit:
```bash
for h in 10.0.20.200 10.0.20.201 10.0.20.202; do
echo "=== $h ==="
ssh root@$h "pct list; qm list"
done
```
---
## Pas 4 — oprirea nodurilor
Ordine: **pveelite (.202) → pve1 (.200) → pvemini (.201)**
pvemini ultimul: e nodul principal și serverul NFS.
GUI: selectezi nodul în arbore → **Shutdown** (dreapta sus).
Așteaptă ca nodul să nu mai răspundă la ping înainte de a-l opri pe următorul.
---
## Repornirea
1. **Pornește toate trei nodurile aproximativ simultan.** Un singur nod pornit
nu are quorum → `/etc/pve` rămâne read-only → nu poți porni niciun guest și
nu poți modifica nimic în GUI.
2. Așteaptă quorum complet:
```bash
ssh root@10.0.20.201 "pvecm status" # Quorate: Yes, Total votes: 3
ssh root@10.0.20.201 "ha-manager status"
```
3. **Pornește guest-urile în ordine inversă:** CT 108 Oracle întâi, apoi VM 201,
apoi restul. Pornirea unui guest HA îi repune state-ul pe `started`.
4. Verifică Oracle:
```bash
ssh root@10.0.20.201 "pct exec 108 -- docker exec oracle-xe bash -lc \
\"printf 'select status from v\\\$instance;\nexit\n' | sqlplus -s / as sysdba\""
```
5. **Re-activează cron-urile** dezactivate la Pasul 1 și job-urile de backup.
6. Verifică replicarea:
```bash
ssh root@10.0.20.201 "pvesr status"
```
Job-urile `*/15` (108, 171, 201) au ratat rulări; recuperează la primul tick.
7. Decide ce faci cu Shutdown Policy — vezi recomandarea de la Pasul 0.
---
## Capcane de mediu
### BIOS „Power On After AC Loss"
Dacă setarea e pe **Power On**, nodurile pornesc singure în secunda în care revine
curentul — posibil eșalonat, posibil înainte să fii tu pregătit. Primul nod care
pornește nu are quorum. Incidentul 2026-04-20 conține exact acest simptom
(„pvemini revine SINGUR — BIOS auto-power-on sau watchdog reset").
Verifică setarea înainte de intervenție sau fii lângă servere la revenirea curentului.
### UPS
Dacă lucrarea implică și UPS-ul, vezi `../ups/README.md` și
`../ups/docs/UPS-SHUTDOWN-README.md` — NUT are propria logică de shutdown
orchestrat care poate intra peste procedura de aici.
---
## Stare de referință a clusterului (2026-08-27)
Resurse HA configurate — 10 în total:
| Serviciu | Nod | Grup | Comentariu |
|----------|-----|------|------------|
| ct:100 | pvemini | ha-prefer-pvemini | portainer |
| ct:101 | pve1 | ha-prefer-pve1 | minecraft |
| ct:103 | pvemini | ha-prefer-pvemini | dokploy |
| ct:104 | pvemini | ha-prefer-pvemini | flowise |
| ct:106 | pvemini | ha-prefer-pvemini | gitea |
| ct:108 | pvemini | ha-prefer-pvemini | central-oracle |
| ct:110 | pve1 | ha-prefer-pve1 | moltbot |
| ct:171 | pvemini | ha-prefer-pvemini | claude-agent |
| vm:109 | pveelite | ha-prefer-pveelite | oracle-dr-windows (`stopped`) |
| vm:201 | pvemini | ha-prefer-pvemini | roacentral |
Guest-uri **în afara** HA: CT 102, CT 301, VM 302, VM 303, VM 310.
`nofailback` este `1` doar pe `ha-prefer-pveelite`; celelalte două grupuri au
`nofailback 0`, deci resursele se întorc automat pe nodul preferat când acesta revine.
---
## Referințe
- [Strategia de failover și HA](../failover/README.md)
- [Incident 2026-04-20 — cluster outage](../incidents/2026-04-20-cluster-outage.md)
- [Cluster README — SSH, storage, noduri](../README.md)
- [UPS](../ups/README.md)