mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-09 18:32:52 +00:00
de7ecee497
* docs: scaffold Tutorials tab and write enroll-a-remote-node Adds the Tutorials tab to docs.json with 15 stub pages across three groups (Fleet & nodes, Deploy & automate, Secure & integrate), and writes the first full tutorial: enrolling a remote node via Pilot Agent mode, verified end to end against a live control instance and a second host running an existing Jellyfin Compose stack. * docs: write Schedule an Operation tutorial * docs: fix MDX parse error in Schedule an Operation tutorial * docs: write Set Up SSO with Custom OIDC tutorial Registers an OAuth client in a self-hosted identity provider (Keycloak worked example), configures Sencho's Custom OIDC settings, tests the connection, and verifies a real end-to-end login with auto-provisioning from two independent surfaces. * docs: drop unused SSO tutorial screenshot sso-settings-empty.png isn't referenced by the tutorial content. * docs: write Set Up Fleet Federation tutorial Migrates a Blueprint-managed workload from one node to another using pin and cordon, with the confirm-before-mutate rollout in between. Corrects the published feature page's claim that pin requires the global admin role; the code gates cordon and pin identically, scoped to the target node. * docs: write Create and Approve a Blueprint tutorial Covers labeling a target node, authoring a stateless Blueprint, walking through the create-then-approve rollout flow, verifying from the Deployments tab and the audit log, and recovering from a port-conflict deploy failure. Cross-links with Move a Blueprint Deployment to a New Node in both directions. * docs: write Automatically Patch a Stack With an Auto-Update Label tutorial * docs: write Configure Auto-Heal Policies tutorial Adds the full step-by-step content for the Configure Auto-Heal Policies stub: an nginx+redis scenario stack, adding a service-scoped policy, and a live verification that breaks a container's healthcheck, confirms the policy restarts it, and recovers it. * docs: write Set Up Deploy Enforcement tutorial Covers configuring a block-on-deploy scan policy against a stack running a deliberately outdated nginx image, reading the block dialog, and overriding it as an admin with the bypass confirmed in the audit log. Includes a stack-pattern mismatch as the most likely first-time failure. * docs: write Configure Environment Guardrails tutorial Covers the Block deploy on missing required env vars guardrail end to end: deploy a Postgres stack with a required password, enable the guardrail, watch a real update get refused with a named-variable message, fix it, and verify from the Activity and Environment tabs. * docs: write Deploy a Stack Automatically From Your CI Pipeline tutorial * docs: write Catch and Fix a Container That's Drifted From Its Compose File tutorial Covers reading a real Drift finding after an out-of-band container change and resolving it by redeploying through Sencho. * docs: write Connect a Git Source tutorial * docs: write Push a Shared Environment File to Every Node tutorial Writes the Fleet Secrets tutorial: create a bundle, target nodes by label, read the push preview/results, verify via the audit log, and recover from a stack-name typo. Removes the three unwritten placeholder stubs (RBAC, Sencho Mesh, private registries) that had no scheduled content.
121 lines
9.0 KiB
Plaintext
121 lines
9.0 KiB
Plaintext
---
|
|
title: Push a Shared Environment File to Every Node Running a Stack
|
|
sidebarTitle: Push shared secrets to your fleet
|
|
description: Author one encrypted env-var bundle on the control instance and push it to a stack running on every labeled node, with a diff you can read before anything is written.
|
|
---
|
|
|
|
Say the same `inventory-api` stack runs on two nodes in your fleet, each with its own `.env` file, and you need to rotate `DB_PASSWORD` on both without SSHing into either host or risking one node drifting out of sync with the other. This walks through building an encrypted secret bundle on your control instance, targeting both nodes by a shared label, and pushing it with a preview step that shows exactly what will change before you write anything.
|
|
|
|
By the end, one bundle holds the source of truth for the stack's environment, and a single push keeps every labeled node's `.env` in sync with it.
|
|
|
|
This tutorial covers creating a bundle, targeting nodes by label, and reading the push preview and results. It doesn't cover importing an existing `.env` from a running stack, editing a bundle to a new version, or the full audit and encryption model; see the [Fleet Secrets](/features/fleet-secrets) feature page for those.
|
|
|
|
## Prerequisites
|
|
|
|
- An **admin** account on the instance you're signed into. Fleet Secrets decrypts and writes credentials fleet-wide, so every route requires an administrator; there is no lesser role that can push a bundle.
|
|
- You're working from the **control instance** (the hub), not a remote node. Fleet Secrets is a hub concern: its API routes never proxy to a remote node, so the **Secrets** tab and its data always reflect the instance you're currently signed into.
|
|
- At least two nodes in your fleet (Local plus one enrolled node), each running a stack with the **same name** and declaring an env file via `env_file:` in its compose. This tutorial uses `inventory-api`:
|
|
|
|
```yaml
|
|
services:
|
|
api:
|
|
image: nginx:alpine
|
|
restart: unless-stopped
|
|
ports:
|
|
- "8099:80"
|
|
env_file:
|
|
- .env
|
|
```
|
|
|
|
Deploy this stack on both nodes before you start (an empty `.env` is fine; the push will populate it). A stack whose compose only has an inline `environment:` block won't show up as a push target, since Fleet Secrets writes to a file, not inline compose values.
|
|
- Both nodes carry a **shared label**. This tutorial uses `inventory` on both. Add labels from **Settings → Nodes** if they aren't set yet.
|
|
|
|
<Note>
|
|
Fleet Secrets is available on every Sencho installation; no Admiral requirement.
|
|
</Note>
|
|
|
|
<Steps>
|
|
<Step title="Open Fleet and create a bundle">
|
|
Open **Fleet**, select the **Secrets** tab, and click **New bundle** (or **Create your first bundle** if this is the first one on the instance).
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/secrets-tab-empty.png" alt="Fleet view with the Secrets tab selected, showing the empty state: heading 'One source of truth for env' and a Create your first bundle button." />
|
|
</Frame>
|
|
|
|
Give the bundle a **Name** (`inventory-api-env` here) and an optional **Description**. Add a `KEY=value` row for each variable the stack needs; click **Add key** for more rows. This tutorial uses `LOG_LEVEL=info`, `REGION=us-east`, and `DB_PASSWORD` set to a placeholder value you'll rotate later. Add a **Change note** describing the initial save.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/create-bundle-filled.png" alt="New secret bundle sheet with Name inventory-api-env, Description 'Shared environment for the inventory-api stack', three key rows LOG_LEVEL=info, REGION=us-east, DB_PASSWORD=change-me-2026, and a change note reading 'Initial inventory-api bundle'." />
|
|
</Frame>
|
|
|
|
Click **Save**. The values are encrypted before the ciphertext is written to disk; the plaintext only lives in the editor while you're filling it in.
|
|
</Step>
|
|
<Step title="Confirm the bundle was saved">
|
|
The bundle now appears as a row in the **Secret bundles** table, at version `v1` with a key count matching what you entered.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/bundle-created.png" alt="Secret bundles table showing one row: inventory-api-env, description 'Shared environment for the inventory-api stack', version v1, 3 keys, with edit, send, and delete icons on the right." />
|
|
</Frame>
|
|
</Step>
|
|
<Step title="Target the push by label and stack name">
|
|
Click the **Send** icon on the bundle's row to open the push wizard. On the **Target** tab, toggle **any** or **all** (any is fine when you have one label) and pick the label both nodes carry, `inventory` here. Enter the **Stack name** the bundle should write to, exactly as it appears on each node. The **Env file** dropdown populates from `env_file:` entries a representative target's compose declares; leave it at `.env` unless your stack uses a different filename.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/push-target.png" alt="Push wizard Target tab. Target nodes section with the any toggle selected and the inventory label chosen. Target stack section with Stack name inventory-api and Env file dropdown showing .env." />
|
|
</Frame>
|
|
|
|
Click **Preview**. This step only reads; it doesn't write anything yet.
|
|
</Step>
|
|
<Step title="Read the preview before writing anything">
|
|
Each row is a node the label selector matched, with a summary of how many keys will be added, changed, or left unchanged. Expand a row to see the per-key breakdown. Since both nodes started with an empty `.env`, every key shows as added.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/push-preview.png" alt="Push wizard Preview tab with two expanded node rows, Local and warehouse-02, each showing +3 added, ~0 changed, ·0 unchanged, and per-key ADDED rows for DB_PASSWORD, LOG_LEVEL, and REGION." />
|
|
</Frame>
|
|
|
|
This is the safety net: the diff shown here is exactly what the next click writes. If a row looks wrong, close the wizard, fix the bundle, and reopen Send to re-run Preview.
|
|
</Step>
|
|
<Step title="Push and confirm the result">
|
|
Click **Push to N nodes**. Sencho writes to each matched node in sequence and reports a per-node outcome on the **Results** tab: a green check with the same added/changed/unchanged counts on success, or a red error with the exact failure string.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/push-results.png" alt="Push wizard Results tab with two green success rows: Local and warehouse-02, each showing +3 ~0 ·0." />
|
|
</Frame>
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Verify it worked
|
|
|
|
Check from two independent surfaces so you're not trusting a single UI element.
|
|
|
|
**The Results tab itself**, shown above: both nodes report success with the counts matching the bundle's key count.
|
|
|
|
**The Audit Log.** Open **More → Audit**. Reading newest first, the top entry reads `pushed secret: 1` and the one just below it `previewed secret push: 1`, both attributed to the account that ran the push.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/audit-log-push.png" alt="Audit log showing two recent entries: 'admin pushed secret: 1' and 'admin previewed secret push: 1', each with a timestamp, node, and 200 status." />
|
|
</Frame>
|
|
|
|
If you have shell access to either node, `cat`-ing the stack's `.env` file is a third way to confirm the write landed, but the two UI surfaces above are enough for day-to-day verification.
|
|
|
|
## If something goes wrong
|
|
|
|
**A node lands in the failed column.** The most common first-time cause is the **Stack name** not matching exactly what's deployed on every target. Retarget the same bundle at a name with a typo, `inventory-apy` instead of `inventory-api`, and Preview still succeeds (it reads an empty, nonexistent file as "nothing set yet" and shows every key as added), but the actual push fails on both nodes: the local node returns an `ENOENT` filesystem error, and the proxied node returns `No env file exists for this stack` over HTTP.
|
|
|
|
<Frame>
|
|
<img src="/images/tutorials/set-up-fleet-secrets/push-failed-typo.png" alt="Push wizard Results tab with two red failure rows: Local showing an ENOENT no such file or directory error, and warehouse-02 showing 'failed to write env (HTTP 404: No env file exists for this stack)'." />
|
|
</Frame>
|
|
|
|
Preview cannot catch this class of mistake because it treats an unreadable target as an empty file rather than a missing stack. Fix the stack name on the Target tab and re-run Preview; a failed push is safe to retry immediately, since the overlay write is idempotent. See [Fleet Secrets · Troubleshooting](/features/fleet-secrets#troubleshooting) for the other common causes, including a stack whose compose doesn't declare the chosen env file at all.
|
|
|
|
## Related
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Fleet Secrets" icon="key-round" href="/features/fleet-secrets">
|
|
Versioning, the import-from-stack flow, concurrency and lifecycle behavior, and the full audit trail.
|
|
</Card>
|
|
<Card title="Enroll a Remote Node" icon="server" href="/tutorials/enroll-a-remote-node">
|
|
Bring a second node into your fleet if you don't have one to label yet.
|
|
</Card>
|
|
</CardGroup>
|