BIT-28 Gate backend startup on migrations
This commit is contained in:
parent
0296280ac9
commit
2015aac8e4
2 changed files with 195 additions and 34 deletions
|
|
@ -13,8 +13,8 @@
|
|||
- Host port 5432 is published only as `127.0.0.1:5432` and is not opened in the
|
||||
NixOS firewall.
|
||||
- Podman reports the service ready only after `pg_isready` succeeds.
|
||||
- PostgreSQL receives `SIGINT` for smart shutdown, with 60 seconds for Podman
|
||||
and 90 seconds for the enclosing systemd service.
|
||||
- PostgreSQL receives `SIGINT` for a clean fast shutdown, with 60 seconds for
|
||||
Podman and 90 seconds for the enclosing systemd service.
|
||||
- Automatic image updates are disabled. Update the digest only in a reviewed
|
||||
change after testing backups, startup, and application compatibility.
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ container startup, the service stages private copies owned by PostgreSQL's uid
|
|||
inside the rootless user namespace. The copies are mounted read-only and are
|
||||
removed from the host runtime directory after PostgreSQL reports healthy and
|
||||
again when the unit stops. The application and migration SOPS files remain
|
||||
available only through their dedicated host groups for the later BIT-28 units.
|
||||
available only through the dedicated groups of their respective host services.
|
||||
|
||||
## Empty-database initialization and privileges
|
||||
|
||||
|
|
@ -67,6 +67,31 @@ objects, roles, or databases and must never run migrations.
|
|||
Initialization scripts run only for an empty volume. Changing a SOPS value does
|
||||
not change a role password in an existing PostgreSQL cluster.
|
||||
|
||||
## Migration-gated backend startup
|
||||
|
||||
`bitcoin-pulse.service` requires `bitcoin-pulse-migrate.service`, and the
|
||||
migration service requires the health-gated PostgreSQL container service. The
|
||||
resulting startup order is:
|
||||
|
||||
```text
|
||||
PostgreSQL healthy -> bounded readiness check -> Migratus -> backend
|
||||
```
|
||||
|
||||
The migration service waits up to 60 seconds for `pg_isready`, then runs the
|
||||
same packaged backend version's `bitcoin-pulse-migrate migrate` command as the
|
||||
unprivileged `bitcoin-pulse-migration` host user. It receives only the migration
|
||||
role and its SOPS password-file path. The backend separately receives the
|
||||
restricted `bitcoin_pulse_app` role and application password-file path.
|
||||
|
||||
The migration unit is a one-shot service without `RemainAfterExit`, so every
|
||||
new start transaction that pulls it in runs Migratus again. Migratus records
|
||||
completed versions in `schema_migrations`; already-applied migrations therefore
|
||||
make repeated starts harmless. A readiness timeout, invalid credential, or
|
||||
migration error fails the one-shot unit. Because the backend is ordered after
|
||||
and requires that unit, the backend process is not started after such a failure.
|
||||
Inspect `journalctl -u bitcoin-pulse-migrate.service` for the bounded readiness
|
||||
message, Migratus error, and systemd exit status.
|
||||
|
||||
## Deployment and verification
|
||||
|
||||
A human must review and merge the change, provision the encrypted keys above,
|
||||
|
|
@ -97,9 +122,9 @@ SELECT has_schema_privilege(
|
|||
'bitcoin_pulse_app', 'public', 'CREATE');
|
||||
```
|
||||
|
||||
The expected results are `true`, `false`, and `false`. After BIT-28 runs the
|
||||
foundation migration, also verify the application can perform only the DML
|
||||
allowed by the migrated schema and that only the migration role can apply DDL.
|
||||
The expected results are `true`, `false`, and `false`. Verify the application
|
||||
can perform only the DML allowed by the migrated schema and that only the
|
||||
migration role can apply DDL.
|
||||
|
||||
To test recreation and persistence, create a temporary probe table as the
|
||||
administrator or migration role, restart the unit, confirm the row remains, and
|
||||
|
|
@ -120,9 +145,41 @@ DROP TABLE bit29_recreation_probe;
|
|||
```
|
||||
|
||||
A normal `systemctl stop` must complete within 90 seconds. Review the journal to
|
||||
confirm a smart PostgreSQL shutdown and no forced kill. Start the unit again and
|
||||
confirm it becomes healthy. Perform these production checks during a reviewed
|
||||
maintenance window.
|
||||
confirm a clean fast PostgreSQL shutdown and no forced kill. Start the unit again
|
||||
and confirm it becomes healthy. Perform these production checks during a
|
||||
reviewed maintenance window.
|
||||
|
||||
After deploying the migration gate, verify the one-shot and backend:
|
||||
|
||||
```console
|
||||
systemctl is-active podman-bitcoin-pulse-postgres.service
|
||||
systemctl is-active bitcoin-pulse.service
|
||||
systemctl show bitcoin-pulse-migrate.service \
|
||||
--property=Result --property=ExecMainStatus
|
||||
journalctl -u bitcoin-pulse-migrate.service -b --no-pager
|
||||
ss -ltn '( sport = :3000 )'
|
||||
```
|
||||
|
||||
A successful migration unit becomes inactive after it exits; `Result=success`
|
||||
and `ExecMainStatus=0` are expected. The backend must be active and port 3000
|
||||
must be bound only to `127.0.0.1`. Restart `bitcoin-pulse.service` once and
|
||||
confirm the migration unit runs successfully again without reapplying completed
|
||||
migrations.
|
||||
|
||||
Successful and repeated paths may be verified during deployment. Exercise the
|
||||
database-unavailable and invalid-migration-credential paths only on a disposable
|
||||
NixOS test host: both must make `bitcoin-pulse-migrate.service` fail, leave
|
||||
`bitcoin-pulse.service` stopped, finish within the configured timeout, and emit
|
||||
an actionable journal message. Never inject invalid credentials into production.
|
||||
|
||||
## Rollback expectations
|
||||
|
||||
A NixOS generation rollback changes the application package and service
|
||||
configuration but does not reverse migrations in PostgreSQL. Do not use
|
||||
`bitcoin-pulse-migrate rollback` as an automatic deployment action. Every schema
|
||||
change must remain compatible with the previous application generation. Use an
|
||||
expand/migrate/contract sequence for breaking changes, and perform any reviewed
|
||||
manual rollback only after assessing data loss and application compatibility.
|
||||
|
||||
## Credential rotation for an existing database
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue