Install HA profile on clean Debian hosts - #888
Conversation
🔐 Codex Security Review
Review SummaryOverall Risk: NONE FindingsNo concrete security, correctness, or reliability issues were identified in the authoritative PR diff. NotesReview was limited to the specified diff. No pool-address or protobuf changes were present. Registry access was unavailable, so the pinned image digests’ platform coverage could not be independently verified. Generated by Codex Security Review | |
There was a problem hiding this comment.
Pull request overview
This PR adds a fleet-ha install workflow to support a one-command local installation of the HA profile onto clean Debian 13 hosts, including role-aware service startup (database vs witness), systemd unit wiring, and updated HA profile artifacts/tests.
Changes:
- Added a host installer (
deployment.Install) that validates platform/host inputs, installs required packages, lays down root-owned release/config paths, and performs an initial start/readiness wait. - Added role-aware service startup/stop entrypoints for systemd (
StartInstalledServices/StopInstalledServices) including etcd quorum + auth-bootstrap coordination. - Updated HA profile artifacts (compose restart policy, systemd ordering, docs/examples) and added installer tests.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
server/internal/ha/deployment/start.go |
New role-aware startup/stop logic for installed HA nodes, including etcd auth bootstrap coordination. |
server/internal/ha/deployment/preflight.go |
Refactors host validation so install can reuse validation without mutating firewall/VIP probing. |
server/internal/ha/deployment/install.go |
New clean-host installer: platform checks, package installation, file/unit installation, image prep, initial start + readiness wait. |
server/internal/ha/deployment/install_test.go |
Adds golden-path installer tests (ordering, witness selection, 16K-page rejection). |
server/cmd/fleet-ha/main.go |
Adds CLI subcommands: install, start, stop, and option parsing. |
deployment-files/ha/tests/test-profile.sh |
Updates static HA profile assertions (restart policy + unit ordering/exec wiring). |
deployment-files/ha/README.md |
Updates operator-facing HA profile install flow documentation. |
deployment-files/ha/proto-fleet-ha.service |
New systemd unit to start HA services with firewall + docker ordering. |
deployment-files/ha/proto-fleet-ha-firewall.service |
New systemd unit to apply nftables rules before HA services/docker. |
deployment-files/ha/node.env.example |
Updates example node env guidance for clean-host install flow. |
deployment-files/ha/keepalived-systemd.conf.tmpl |
Adds unit dependencies so keepalived starts after HA services. |
deployment-files/ha/fleet-compose.yaml |
Minor compose cleanup in HA fleet overlay. |
deployment-files/ha/compose.yaml |
Adds restart: always to etcd/Patroni services for resilience. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a5a95587d5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
a5a9558 to
19afb50
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 19afb509a4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
19afb50 to
10499c6
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10499c6d12
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
10499c6 to
1db9142
Compare
1db9142 to
32a6e7a
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 32a6e7a048
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
32a6e7a to
a27e256
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a27e256ac5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bd2c3ce3c9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 57459a4df5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 03b0878bd8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Reviewable diff: +1494/-173 across 21 files (excludes generated, test, and story files).
Summary
Adds
fleet-ha installfor one-command local installation on clean Debian 13 amd64 or arm64 hosts with 4096-byte pages. It validates the host and release, installs the supported packages, persists protected configuration and service ordering, starts only the node's required services, and ends withfleet-ha status --check.Stack: #887 -> #888 -> #889 -> #890 -> #891 -> #892. This diff is relative to #887 and uses its status command as the final readiness check. Qualification is deferred to #889; application updates are deferred to #890 and #891.
How it works
An operator copies a release, one host-specific
node.env, and the matching secrets to each host, then runsfleet-ha installlocally. Preflight rejects unsupported platforms, 16K pages, invalid routes or ports, malformed secrets, non-empty HA data directories, stale service overrides, incomplete release artifacts, and a missing HA database image reference before broad package mutation. The offline etcd root password must use the generator's 32-byte lowercase-hex format and differ from every service password and the Fleet JWT signing secret in the host bundle. If the VIP is already present during concurrent installation, ARP must show that it uses the same physical MAC as the configured peer's stable IP; any other owner is rejected. The installer masks Docker and keepalived while packages are installed, applies the firewall first, loads and verifies the exact HA database image named by the packaged Compose file, and prepares the Fleet images. It installs the Docker recovery dependency before etcd first starts, so a Docker or host restart must re-enter the authentication gate. etcd and Patroni use process-failure-only restart policies, so Docker cannot restore them before the HA authentication gate; Docker restart propagation restarts the HA unit after the daemon returns. The installer then starts HA temporarily, proves failover readiness, and enables normal boot persistence. Early snapshot cleanup and later service cleanup use fresh bounded contexts, even after installation is canceled. The first database host rejects principals outside the fixed Fleet allowlist after quorum, clears only an incomplete allowlisted etcd policy, rebuilds its roles, users, and grants from the installed secrets, enables authentication, and verifies all three credentials; peers wait rather than running a second initializer.flowchart TD I["fleet-ha install node.env"] --> P["Validate clean host and release"] P --> F["Install packages while services are masked"] F --> N["Apply firewall and protected files"] N --> E["Start Docker and etcd"] E --> R{"Node role"} R -->|database| D["Start Patroni, Fleet, keepalived"] R -->|witness| W["Keep etcd only"] D --> S["fleet-ha status --check"]Areas of the code involved
server/internal/ha/deployment/install.goserver/internal/ha/deployment/start.goserver/cmd/fleet-ha/Key technical decisions & trade-offs
sudo; the operator is not added to the Docker group and does not reconnect.Testing & validation
deployment-files/ha/tests/test-profile.shpass.