19.6 用声明式清单交付两个服务单元
声明式交付的核心不是“YAML 很先进”,而是让目标、作用域、版本、差异与 执行证据可以评审。inventory 是意图,不是已经发生的事实。
19.6.1 inventory、参数模板与主机分组
inventory 同时承载图和参数
Pigsty inventory 的结构大致是:
all:
children:
infra:
hosts: ...
etcd:
hosts: ...
pg-meta:
hosts: ...
vars:
pg_cluster: pg-meta
pg-test:
hosts: ...
vars:
pg_cluster: pg-test
vars:
version: v4.4.0
pg_version: 18它表达两类信息:
membership graph
哪些 host 属于哪些 module/cluster
desired parameters
version, paths, packages, tuning, users, DBs, services, access混在一个文件里不表示它们的生命周期相同。host identity 可能多年稳定, password 要轮换,service definition 会迭代,初始化参数只在新 cluster 生效。
identity 参数必须明确
Pigsty 的参数层次包含 global、group/cluster、host/instance 等作用域。对 PostgreSQL member,核心 identity 至少有:
pg_cluster: pg-test
pg_seq: 1
pg_role: primary官方
Pigsty parameter model
将 pg_cluster、pg_seq、pg_role 等视为无默认值的 identity 参数。
没有 identity,不应让自动化猜:
- 这是哪个 HA group;
- member 名是什么;
- bootstrap primary 是谁;
- service/monitor/backup 如何命名。
参数优先级要可解释
同一参数可能来自:
role default
global vars
module/group vars
cluster vars
host vars
extra vars
generated template
runtime dynamic config最终值要能回答:
value
source
scope
owner
change context
rendered destination
live observed value“我在 YAML 里搜不到”不等于它使用 PostgreSQL 默认;可能来自 role default 或 template。
本章 live inventory 没有重复声明每一个 role default。验收从 SQL读取 checksum、locale、timezone 等结果,避免把“省略”误作“不确定”或 “一定是 PostgreSQL 默认”。
参数模板是起点,不是服务等级
pg_conf: oltp.yml 可提供合理 OLTP 起点,node_tune: oltp 可收敛主机
baseline。它们不包含业务 workload evidence。
模板不能自动知道:
peak TPS and query mix
working set
connection fan-out
storage latency
WAL generation
RPO/RTO
maintenance workload
tenant contention第 26、27 章才通过压力与瓶颈证据调参。
从 exact release 生成配置
本章没有直接运行当前 dirty checkout,而是:
git archive v4.4.0解到私有临时目录,并记录 tag commit:
2d5a45f759274048de0c197829228a71d0182e5c然后:
./configure -c ha/full -s -n -g -v 18 -r default参数含义:
-c ha/full 使用四节点功能演示模板
-s 跳过 IP 探测/替换
-n 非交互
-g 生成随机密码
-v 18 PostgreSQL major 18
-r default 默认上游仓库区域ha/full 官方定位主要是演示与测试,不是生产拓扑模板;它把 infra、单 etcd、
MinIO 和 pg-meta 放在第一节点,pg-test 放在后面三节点。这正是本章
将其标为 sandbox 的原因。
generator output 必须 review
wizard 给出初稿后,逐项 review:
source release
target addresses and SSH user
OS/architecture
module membership
PostgreSQL major/locale/checksum
storage paths
cluster/member identity
service/offline placement
repo/mirror/proxy
secrets
safeguards
backup target
monitoring retention
firewall/accessconfigure 成功只表示生成文件,不表示目标可部署。
live inventory 是 secret-bearing artifact
随机密码比模板默认密码安全,但文件仍含 secret。处理:
mode 0600
private temporary/secret-managed path
never paste full file into issue/chat/log
never commit
rotate if exposed
production uses secret authority and lifecycle本次初始化过程中,首次生成的凭据曾出现在工具输出边界;因此立即重新生成, 正式 live inventory 使用另一组未打印的值。这个事件提醒我们:
redaction 不是最后一步;command output、debug、diff 和 CI log 都是泄露面。
只导出 allowlist projection
inventory_projection.py 读取 live
inventory,只保留:
Pigsty/PostgreSQL/locale non-secret globals
host set and group membership
cluster/member role/offline flags
source mode and a withheld source-fingerprint marker
safe projection checksum in the capture manifest
redacted secret-field count
secret_values_exported=0它不使用“把已知 password 字段替换为星号后整份输出”的 denylist 模式。 denylist 容易漏掉新字段;allowlist 默认拒绝未知内容。
执行:
export PG36_CH19_INVENTORY=/absolute/private/pg36.yml
export PG36_EVIDENCE_DIR=/absolute/evidence/ch19
static/labs/ch19/task.sh project投影不是可用于部署的 inventory,故意不可逆。
sanitized example 只表示形状
inventory.example.yml 使用 sentinel
secret,帮助理解结构。它不应原样部署。
审阅 example 时也要防止:
真实 address/owner accidentally copied
有效 token/password
private key
internal repository credential
production backup endpointinventory 是 code,但不等于把一切都放 Git
适合版本化:
schema and groups
non-secret desired parameters
service definitions
role/database declarations without secret values
policy IDs
change history需要受控 secret store:
password
private key
recovery secret
API token
CA signing key
KMS credential需要外部事实系统:
asset/failure-domain inventory
IPAM/DNS authority
owner/on-call
certificate issuance
package artifact promotion声明式不是单文件崇拜,而是让 authority 可追踪。
19.6.2 生产服务与隔离验证服务
先澄清本节标题的边界
生产设计应该区分:
application service unit
platform/control/validation unit本章用 pg-test 和 pg-meta 演练这种分工,但两者都位于 disposable
sandbox:
production_data_permitted=false
production_traffic_permitted=false所以 pg-test 是 production-shaped teaching service,不是生产服务;
pg-meta 也不是合格的生产 control plane。
服务单元一:pg-test
声明:
pg-test:
hosts:
10.10.10.11:
pg_seq: 1
pg_role: primary
10.10.10.12:
pg_seq: 2
pg_role: replica
10.10.10.13:
pg_seq: 3
pg_role: replica
pg_offline_query: true
vars:
pg_cluster: pg-test目的:
three-member topology
primary/replica service rehearsal
offline placement rehearsal
chapter 20 fault target
chapter 21 recovery target
chapter 22 endpoint target当前 bootstrap role:
.11 primary
.12 replica
.13 replica/offlinefuture failover 后 runtime role 可能变化;inventory declaration 与 observed role 的解释要跟着 chapter 20 contract 更新。
服务单元二:pg-meta
声明:
pg-meta:
hosts:
10.10.10.10:
pg_seq: 1
pg_role: primary
vars:
pg_cluster: pg-meta同一 node 还承载:
Pigsty infra
single etcd member
MinIO
monitoring/logging
admin source它可用于控制与验证,但这个共置形成大 blast radius。不要把“组件齐全”解释为 “组件高可用”。
两个 service unit 必须有不同 system identifier
部署时如果错误 clone 同一 cluster,再改名字,表面可能出现两个 group。 因此验收要求:
system_id(pg-meta) != system_id(pg-test)同时:
system_id(pg-test-1)
= system_id(pg-test-2)
= system_id(pg-test-3)这是 declaration 和 physical lineage 的交叉检查。
control data 与 application data 不要无意混合
真实平台需要决定:
Pigsty metadata DB 是否与业务 cluster 分离
monitoring outage 是否影响 DB availability
backup repository failure 是否影响 primary
DCS failure 是否影响 existing traffic/new failover
control credentials 是否能访问 business data
control-plane maintenance blast radius本沙箱共置是资源选择,不是推荐生产答案。
offline 服务不等于隔离环境
.13 是 replica + offline query 标记。它仍:
接收同一 WAL
占同一 laptop CPU/storage
依赖同一 DCS
可能被 direct access
可能因慢查询产生 recovery conflict要实现更强隔离,可能需要:
dedicated host/failure domain
cgroup/resource limits
separate service/HBA/role
query timeout
replication/freshness SLO
dedicated cluster or analytical systemproduction topology 要替换六个例外
从本章沙箱走向生产,不是删除 sandbox 字样。至少解决:
independent failure domains
etcd quorum
backup target/DR independence
qualified storage
secret authority/rotation
measured resource capacity并完成后续章节 gate。
service unit review 表
| 问题 | pg-meta | pg-test |
|---|---|---|
| authority | control/validation | teaching application service |
| members | 1 | 3 |
| current primary | .10 | .11 |
| replicas | 0 | .12, .13 |
| offline placement | no | .13 |
| system ID | own | shared within three members |
| production SLO | none | none |
| later fault target | limited | chapter 20 |
这张表应进入 design review,而不是从 Ansible recap 猜。
19.6.3 幂等部署、差异检查与失败重跑
幂等的正确含义
理想的 idempotent task:
run desired convergence once -> target state
run again without input/drift -> no material change但整套部署包含:
package repositories
generated secrets/certificates
database initialization
backup creation
monitoring registration
external APIs
service restarts
time-dependent facts所以不能用“Ansible 是幂等的”替代每个 action 的语义。
Pigsty 官方
Playbooks
说明大多数 playbook 可重复运行,同时指出清理参数和 *-rm.yml 等有重要
caveat。
一次完整部署的受控顺序
本章实际流程:
1. resolve/extract exact release
2. generate and review private inventory
3. direct SSH ping four identities
4. copy exact release + private inventory to admin node
5. bootstrap admin prerequisites
6. run ./deploy.yml -i pg36.yml
7. retain private log and return code
8. capture only safe recap
9. read-only L2 evidence capture
10. positive + negative validation and reviewPigsty deploy.yml 是 core chain 的 one-pass deployment。它完成很多工作,
不意味着每个业务 policy 自动满足。
recap 是执行证据,不是服务验收
本次安全 recap:
| target | ok | changed | unreachable | failed |
|---|---|---|---|---|
10.10.10.10 | 326 | 248 | 0 | 0 |
10.10.10.11 | 174 | 134 | 0 | 0 |
10.10.10.12 | 159 | 120 | 0 | 0 |
10.10.10.13 | 159 | 120 | 0 | 0 |
localhost | 6 | 4 | 0 | 0 |
它证明 playbook 没报告 failed/unreachable。它不证明:
correct target identity
correct locale/checksum
one leader
replication healthy
service routing
production capacity
backup restore
HA behavior这些另行验收。
changed=0 也不是唯一幂等标准
一些 task 合理地每次:
refresh facts
check service
render timestamped artifact
probe endpoint
rotate ephemeral state也有 task 误报 changed。应关注:
unplanned service restart
config checksum drift
package version change
database reinitialization
role/permission mutation
secret rotation
endpoint outage二次执行前先查 playbook/tag 的语义,不以追求漂亮 recap 为目标。
失败重跑前先分类
失败类型:
| 类型 | 例子 | 下一步 |
|---|---|---|
| transient | repo timeout、短暂 DNS | 保存证据后 bounded retry |
| declaration | wrong group/var | 修 inventory,review diff |
| prerequisite | sudo/clock/disk | 修前提并重新 preflight |
| partial init | primary created, replica failed | 查 cluster state,按 role runbook |
| incompatible | package/extension/OS | 停止,修矩阵 |
| destructive drift | wrong target/data exists | 停止并升级决策 |
| secret exposure | log printed credential | 先 rotate/contain |
不要在不知道已执行到哪里时直接:
rm -rf PGDATA
pgsql-rm
wipe/reconfigure all失败现场是证据。
限制 scope
Pigsty playbook支持 Ansible -l 与 tags。例:
./pgsql.yml -i private.yml -l pg-test
./pgsql.yml -i private.yml -l 10.10.10.13
./pgsql.yml -i private.yml -l pg-test -t pg_service使用前必须确认:
inventory exact path
limit resolves to expected hosts
tag dependencies
check/diff support and limitations
serial/batch behavior
current member role
change authority-l pg-test 是作用域控制,不是安全沙箱。
diff 不能泄密
安全 diff 分层:
secret-free projected inventory diff
rendered config hash/semantic diff
live pg_settings diff excluding secrets
package/version diff
service membership diff
policy exception diff不要把 live inventory git diff、Ansible -vvv、template variables 或
.pgpass 直接上传。
automatic reboot 被刻意拒绝
bootstrap 观察到 meta 节点已安装 kernel 与当前 running kernel 有差异。这 可能要求 reboot 才完成 host baseline,但本章没有自动重启:
- reboot 会改变运行状态;
- control/infra/DB 共置;
- 尚未建立第 20 章 HA 行为证据;
- maintenance authority 未授予;
- 本章 deployment 成功不要求偷偷消除 warning。
正确做法是登记 exception/change,计划可观察的 reboot,而不是为了让 preflight 变绿直接执行。
normal lab 没有 deploy action
task.sh 只提供:
project
capture
verify
review
all
reset:cluster其中 all 只读。没有 deploy 是有意设计:
source-controlled 验收脚本不应在读者以为“检查环境”时顺便收敛 package、 重启服务或重建数据库。
部署需要独立变更窗口和 runbook。
removal playbook 是 destructive action
Pigsty pgsql-rm.yml 用于移除 cluster/instance。官方文档说明 production
应显式启用 pg_safeguard,并对 override 格外谨慎。
本章只提供多重 guard 的
reset-cluster.sh,没有运行它。它要求:
exact sandbox target
exact reset token
no production data assertion
clients drained assertion
exact release/inventory
prior machine-ID allowlist
fresh passing evidence
interactive second ACK这是演示 destructive contract,不是授权。
交付完成定义
声明式交付完成需同时满足:
source pinned
inventory reviewed and secret-safe
target identity proven
playbook rc/recap retained
live host facts pass
PostgreSQL init contract pass
Patroni/SQL/inventory topology agree
endpoint identity observable
exceptions accepted by owners
rollback/reset boundary explicit
later gates remain named本章环境满足 sandbox L2,带六个 exception;production gate 仍 pending。
上一节:拓扑、命名与故障域 · 返回本章目录 · 下一节:实战:L2 部署验收 · 查看全书目录 · 查看索引中心