Skip to content

Commit 55c3b0b

Browse files
docs: add comprehensive user-centric documentation
Create 13 interconnected documentation files covering the full feature set: getting started, architecture, core concepts, configuration, deployments, security, observability, integrations, node management, operations, API reference, and advanced topics.
1 parent 00119db commit 55c3b0b

13 files changed

Lines changed: 3836 additions & 0 deletions

docs/advanced-topics.md

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
# Advanced Topics
2+
3+
This guide covers the node fleet simulator, service topology visualization, config validation rules, and troubleshooting.
4+
5+
## Node Fleet Simulator
6+
7+
The control plane includes a built-in simulator for spawning virtual Sentinel nodes. This is useful for testing rollouts, drift detection, and dashboards without deploying real proxy instances.
8+
9+
### Spawning Simulated Nodes
10+
11+
From an IEx console:
12+
13+
```elixir
14+
alias SentinelCp.Simulator.Fleet
15+
16+
# Spawn 10 simulated nodes for a project
17+
{:ok, nodes} = Fleet.spawn_nodes("my-project", 10,
18+
base_url: "http://localhost:4000",
19+
name_prefix: "sim-node",
20+
poll_interval_ms: 5000,
21+
heartbeat_interval_ms: 10000,
22+
apply_delay_ms: 1000,
23+
failure_rate: 0.0
24+
)
25+
```
26+
27+
### Simulator Options
28+
29+
| Option | Default | Description |
30+
|--------|---------|-------------|
31+
| `base_url` | `http://localhost:4000` | Control plane URL |
32+
| `name_prefix` | `sim-node` | Prefix for node names (e.g., `sim-node-001`) |
33+
| `poll_interval_ms` | `5000` | How often nodes poll for bundle updates |
34+
| `heartbeat_interval_ms` | `10000` | How often nodes send heartbeats |
35+
| `apply_delay_ms` | `1000` | Simulated delay for applying a bundle |
36+
| `failure_rate` | `0.0` | Probability (0.0-1.0) that bundle apply fails |
37+
38+
### Simulated Node Lifecycle
39+
40+
Each simulated node runs as a GenServer and follows this lifecycle:
41+
42+
1. **Register** — Calls the registration API, receives `node_id` and `node_key`
43+
2. **Heartbeat** — Sends periodic heartbeats with simulated health metrics (CPU, memory, uptime)
44+
3. **Poll** — Checks for new bundles via the polling API
45+
4. **Apply** — When a new bundle is detected, simulates applying it (with optional delay and failure)
46+
47+
### Managing the Fleet
48+
49+
```elixir
50+
# Check fleet status
51+
Fleet.get_summary(nodes)
52+
# => %{total: 10, connected: 10, disconnected: 0, initializing: 0, stopped: 0}
53+
54+
# Get detailed state of all nodes
55+
Fleet.get_all_states(nodes)
56+
57+
# Trigger random failures (simulates 3 nodes failing)
58+
Fleet.trigger_random_failures(nodes, 3)
59+
60+
# Stop all simulated nodes
61+
Fleet.stop_all(nodes)
62+
```
63+
64+
### Testing Rollouts with the Simulator
65+
66+
1. Spawn a fleet of simulated nodes
67+
2. Create and compile a bundle
68+
3. Create a rollout targeting all nodes
69+
4. Watch the rollout progress in the UI as simulated nodes apply the bundle
70+
5. Set `failure_rate: 0.1` to test health gate failures and auto-rollback
71+
72+
## Service Topology
73+
74+
The topology view provides a visual representation of your service graph, showing how services, upstream groups, and targets relate to each other.
75+
76+
### What Topology Shows
77+
78+
- **Services** as nodes in the graph with their route paths
79+
- **Upstream groups** linked to services that use them
80+
- **Upstream targets** showing individual backend servers
81+
- **Middlewares** attached to services
82+
- **Auth policies** and **WAF policies** linked to services
83+
- **Certificates** associated with services
84+
85+
### Accessing Topology
86+
87+
Navigate to your project and click **Topology** in the sidebar. The graph updates in real-time as you add or modify resources.
88+
89+
## Config Validation Rules
90+
91+
Projects can define custom validation rules that are checked during bundle compilation.
92+
93+
### Rule Types
94+
95+
#### Required Field
96+
97+
Ensures a specific field or block exists in the KDL configuration:
98+
99+
```json
100+
{
101+
"rule_type": "required_field",
102+
"name": "Require rate limiting",
103+
"pattern": "rate_limit",
104+
"severity": "error"
105+
}
106+
```
107+
108+
#### Forbidden Pattern
109+
110+
Rejects configurations containing a regex pattern:
111+
112+
```json
113+
{
114+
"rule_type": "forbidden_pattern",
115+
"name": "No debug mode",
116+
"pattern": "debug\\s+(true|enabled)",
117+
"severity": "error"
118+
}
119+
```
120+
121+
#### Allowed Pattern
122+
123+
Requires the configuration to match a regex pattern:
124+
125+
```json
126+
{
127+
"rule_type": "allowed_pattern",
128+
"name": "Must have health check",
129+
"pattern": "health_check\\s+\\{",
130+
"severity": "warning"
131+
}
132+
```
133+
134+
#### Max Size
135+
136+
Limits the configuration file size:
137+
138+
```json
139+
{
140+
"rule_type": "max_size",
141+
"name": "Config size limit",
142+
"config": {"max_bytes": 102400},
143+
"severity": "error"
144+
}
145+
```
146+
147+
#### JSON Schema
148+
149+
Validates the configuration against a JSON schema:
150+
151+
```json
152+
{
153+
"rule_type": "json_schema",
154+
"name": "Schema compliance",
155+
"config": {
156+
"schema": {
157+
"type": "object",
158+
"required": ["route"]
159+
}
160+
},
161+
"severity": "error"
162+
}
163+
```
164+
165+
### Severity Levels
166+
167+
| Severity | Compilation Effect |
168+
|----------|-------------------|
169+
| `error` | Fails compilation |
170+
| `warning` | Compilation succeeds with warnings |
171+
| `info` | Informational only |
172+
173+
### Managing Rules
174+
175+
Rules are managed per project via the UI or API. Each rule can be independently enabled or disabled.
176+
177+
## Bundle Promotion Pipeline
178+
179+
Bundles progress through environments in a defined order:
180+
181+
### Promotion Flow
182+
183+
```
184+
1. Bundle compiled
185+
2. Promote to dev (ordinal 0)
186+
└── Deploy via rollout to dev nodes
187+
3. Promote to staging (ordinal 1)
188+
└── Deploy via rollout to staging nodes
189+
4. Promote to production (ordinal 2)
190+
└── Deploy via rollout to production nodes
191+
```
192+
193+
### Promotion Rules
194+
195+
- Bundles must be promoted in ordinal order (can't skip environments)
196+
- Each promotion creates a `BundlePromotion` record with who promoted and when
197+
- A bundle can only be promoted to each environment once
198+
- Use `promote_bundle_to_next` to automatically promote to the next environment
199+
200+
### Viewing Promotion History
201+
202+
Each bundle shows its promotion timeline: which environments it has been promoted to, by whom, and when.
203+
204+
## KDL Configuration Generation
205+
206+
When services, upstreams, certificates, and other resources are defined in the control plane, they are compiled into KDL (KNode Document Language) configuration for the Sentinel proxy.
207+
208+
### How It Works
209+
210+
The compiler:
211+
212+
1. Reads all enabled services for the project, ordered by position
213+
2. Generates KDL `route` blocks with upstream, timeout, retry, cache, and other settings
214+
3. Includes middleware configurations in the processing chain
215+
4. References certificates by their slugs
216+
5. Injects auth policy and WAF policy configurations
217+
6. Includes internal CA certificates as extra files
218+
7. Collects and includes plugin files
219+
220+
### Generated Structure
221+
222+
```kdl
223+
// Generated from service "API Backend"
224+
route "/api/*" {
225+
upstream "http://api.internal:8080"
226+
timeout 30
227+
retry {
228+
attempts 3
229+
backoff "exponential"
230+
}
231+
rate_limit {
232+
requests 100
233+
window "1m"
234+
}
235+
}
236+
```
237+
238+
## Risk Scoring Details
239+
240+
Every compiled bundle is automatically scored for risk by comparing it against the previous bundle.
241+
242+
### Risk Factors
243+
244+
| Factor | Risk Level | Detection |
245+
|--------|-----------|-----------|
246+
| Auth policy changed | High | Auth/authentication/authorization blocks differ |
247+
| TLS config changed | High | TLS blocks differ |
248+
| Upstream removed | Medium | Upstream blocks disappeared |
249+
| Rate limit changed | Medium | Rate limit blocks differ |
250+
| Many route changes | Medium | >10 routes added or removed |
251+
252+
### How Scores Are Used
253+
254+
- **Risk level** is displayed in the bundle list and detail views
255+
- **Risk reasons** explain what triggered the assessment
256+
- High-risk bundles may warrant additional review or approval before deployment
257+
- Risk scores are included in notification payloads
258+
259+
## Troubleshooting
260+
261+
### Bundle Compilation Fails
262+
263+
**Symptom**: Bundle status stays at `compiling` or transitions to `failed`.
264+
265+
**Check**:
266+
1. Ensure the `sentinel` binary is available at the configured `SENTINEL_BINARY` path
267+
2. Check the bundle's `error` field for validation messages
268+
3. Review the Oban job logs for `CompileWorker` failures
269+
270+
### Nodes Not Appearing Online
271+
272+
**Symptom**: Registered nodes show as `offline` or `unknown`.
273+
274+
**Check**:
275+
1. Verify the node can reach the control plane URL
276+
2. Check the node's authentication (key or JWT)
277+
3. Ensure heartbeats are being sent (check the heartbeat interval)
278+
4. The staleness threshold is 120 seconds — nodes must heartbeat within this window
279+
280+
### Rollout Stuck
281+
282+
**Symptom**: Rollout stays in `running` but doesn't progress.
283+
284+
**Check**:
285+
1. Verify target nodes are online and heartbeating
286+
2. Check health gates — a failing gate will pause progression
287+
3. Review the current step's state and any error messages
288+
4. Check the `progress_deadline_seconds` — steps fail after this deadline
289+
5. Look for the `RolloutTickWorker` in the Oban dashboard
290+
291+
### Drift Events Not Resolving
292+
293+
**Symptom**: Drift events remain active even though nodes are running the expected bundle.
294+
295+
**Check**:
296+
1. Verify the node's `active_bundle_id` matches `expected_bundle_id`
297+
2. The `DriftWorker` auto-resolves synchronized nodes on its next run (every 30 seconds)
298+
3. If `drift_auto_remediation` is enabled, check that remediation rollouts are completing
299+
300+
### Notifications Not Delivered
301+
302+
**Symptom**: Events occur but no notifications are received.
303+
304+
**Check**:
305+
1. Verify the notification channel is enabled and configured correctly
306+
2. Test the channel using the test function
307+
3. Check delivery attempt records for error messages
308+
4. Review the dead-letter queue for failed deliveries
309+
5. Ensure a notification rule exists with a matching event pattern
310+
311+
### Database Performance
312+
313+
**Check**:
314+
1. Monitor Ecto query metrics via Prometheus (`ecto_query_total_time`)
315+
2. Check the connection pool size (`POOL_SIZE` environment variable)
316+
3. For large fleets, ensure metrics rollup and cleanup workers are running
317+
4. Old heartbeat and event records are pruned automatically (1,000 heartbeats, 500 events per node)
318+
319+
### Memory Usage
320+
321+
**Check**:
322+
1. Monitor BEAM VM metrics via Prometheus (`beam_memory_*`)
323+
2. Large fleets with frequent heartbeats may need tuning of heartbeat intervals
324+
3. Check for accumulating Oban jobs in the queue
325+
4. The simulator spawns GenServer processes per node — stop unused simulators

0 commit comments

Comments
 (0)