Files
cli/docs/service-discovery-labels.md

314 lines
14 KiB
Markdown
Raw Normal View History

# Sunbeam Service Discovery Labels
Migration guide: replacing hardcoded service definitions in `sunbeam-sdk/src/registry/services.rs` with Kubernetes label-based discovery.
---
## 1. Label Convention
Every Sunbeam-managed service must have labels and annotations on its **primary Kubernetes resource** (Deployment, StatefulSet, DaemonSet, or CNPG Cluster).
### Labels (required)
| Label | Value | Purpose |
|---|---|---|
| `sunbeam.pt/service` | Service name (e.g. `hydra`) | Primary lookup key for the CLI |
| `sunbeam.pt/category` | Category slug (e.g. `auth`) | Grouping for `sunbeam status`, `sunbeam restart <category>` |
### Annotations (conditional)
| Annotation | Value | When to include |
|---|---|---|
| `sunbeam.pt/display-name` | Human-readable name (e.g. `"Hydra (OAuth2/OIDC)"`) | Always |
| `sunbeam.pt/kv-path` | OpenBao KV v2 secret path (e.g. `hydra`) | Only if the service has secrets in OpenBao |
| `sunbeam.pt/db-user` | PostgreSQL username (e.g. `hydra`) | Only if the service has a CNPG database |
| `sunbeam.pt/db-name` | PostgreSQL database name (e.g. `hydra_db`) | Only if the service has a CNPG database |
| `sunbeam.pt/build-target` | Build target name (e.g. `people`) | Only if the service is built from source |
| `sunbeam.pt/depends-on` | Comma-separated service names (e.g. `postgres,openbao`) | Only if the service has dependencies |
| `sunbeam.pt/health-check` | One of: `pod-ready`, `cnpg`, `seal-status`, or an HTTP path like `/healthz` | Only if not the default (`pod-ready`). Omit for services with `HealthCheck::None` |
### Virtual services
Services with **no workload pods** (e.g. `scaleway-s3`, `longhorn`) should be represented by a ConfigMap carrying the labels and an additional marker:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: sunbeam-svc-scaleway-s3
namespace: external
labels:
sunbeam.pt/service: scaleway-s3
sunbeam.pt/category: infra
sunbeam.pt/virtual: "true"
annotations:
sunbeam.pt/display-name: "Scaleway S3"
sunbeam.pt/kv-path: scaleway-s3
data: {}
```
### Multi-deployment services
When a service spans multiple Deployments (e.g. `messages` has `messages-backend`, `messages-mta-in`, `messages-mta-out`), **all** Deployments get the **same** `sunbeam.pt/service` label. The CLI groups them automatically. Put the full annotations on just one of them (conventionally the primary/backend Deployment) and minimal labels on the rest.
---
## 2. Complete Service Table
33 services organized by category. The "K8s Resource" column indicates which object to label.
### Auth (namespace: `ory`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `hydra` | Deployment `hydra` in `ory` | `service: hydra`, `category: auth` | `display-name: "Hydra (OAuth2/OIDC)"`, `kv-path: hydra`, `db-user: hydra`, `db-name: hydra_db`, `depends-on: postgres,openbao` | |
| `kratos` | Deployment `kratos` in `ory` | `service: kratos`, `category: auth` | `display-name: "Kratos (Identity)"`, `kv-path: kratos`, `db-user: kratos`, `db-name: kratos_db`, `depends-on: postgres,openbao` | |
| `login-ui` | Deployment `login-ui` in `ory` | `service: login-ui`, `category: auth` | `display-name: "Login UI"`, `kv-path: login-ui`, `depends-on: kratos` | |
### Data (namespace: `data`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `postgres` | CNPG Cluster `postgres` in `data` | `service: postgres`, `category: data` | `display-name: "PostgreSQL (CNPG)"`, `health-check: cnpg` | Health check is `cnpg`, not `pod-ready` |
| `openbao` | StatefulSet `openbao` in `data` | `service: openbao`, `category: data` | `display-name: "OpenBao (Secrets)"`, `health-check: seal-status` | Health check is `seal-status` |
| `valkey` | Deployment `valkey` in `data` | `service: valkey`, `category: data` | `display-name: "Valkey (Cache)"` | |
| `opensearch` | Deployment `opensearch` in `data` | `service: opensearch`, `category: data` | `display-name: "OpenSearch"` | |
### DevTools (namespace: `devtools`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `gitea` | Deployment `gitea` in `devtools` | `service: gitea`, `category: devtools` | `display-name: "Gitea (Git Forge)"`, `kv-path: gitea`, `db-user: gitea`, `db-name: gitea_db`, `depends-on: postgres,openbao` | |
### Platform (namespace: `lasuite`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `hive` | Deployment `hive` in `lasuite` | `service: hive`, `category: platform` | `display-name: "Hive (Backend)"`, `kv-path: hive`, `db-user: hive`, `db-name: hive_db`, `depends-on: postgres,openbao` | |
| `people-backend` | Deployment `people-backend` in `lasuite` | `service: people-backend`, `category: platform` | `display-name: "People (Backend)"`, `kv-path: people`, `db-user: people`, `db-name: people_db`, `build-target: people`, `depends-on: postgres,openbao` | |
| `people-frontend` | Deployment `people-frontend` in `lasuite` | `service: people-frontend`, `category: platform` | `display-name: "People (Frontend)"`, `build-target: people-frontend` | |
| `people-celery` | Deployments `people-celery-worker` + `people-celery-beat` in `lasuite` | `service: people-celery`, `category: platform` | `display-name: "People (Workers)"`, `depends-on: people-backend` | Multi-deploy: both Deployments get the same `service` label |
| `docs` | Deployment `docs-frontend` in `lasuite` | `service: docs`, `category: platform` | `display-name: "Docs"`, `kv-path: docs`, `db-user: docs`, `db-name: docs_db`, `build-target: docs-frontend`, `depends-on: postgres,openbao` | |
| `meet` | Deployment `meet` in `lasuite` | `service: meet`, `category: platform` | `display-name: "Meet"`, `kv-path: meet`, `db-user: meet`, `db-name: meet_db`, `build-target: meet`, `depends-on: postgres,openbao,livekit` | |
| `drive` | Deployment `drive` in `lasuite` | `service: drive`, `category: platform` | `display-name: "Drive"`, `kv-path: drive`, `db-user: drive`, `db-name: drive_db`, `depends-on: postgres,openbao` | |
| `projects` | Deployment `projects` in `lasuite` | `service: projects`, `category: platform` | `display-name: "Projects"`, `kv-path: projects`, `db-user: projects`, `db-name: projects_db`, `build-target: projects`, `depends-on: postgres,openbao` | |
| `calendars` | Deployment `calendars` in `lasuite` | `service: calendars`, `category: platform` | `display-name: "Calendars"`, `kv-path: calendars`, `db-user: calendars`, `db-name: calendars_db`, `build-target: calendars`, `depends-on: postgres,openbao` | |
| `kratos-admin` | Deployment `kratos-admin` in `lasuite` | `service: kratos-admin`, `category: platform` | `display-name: "Kratos Admin UI"`, `kv-path: kratos-admin`, `build-target: kratos-admin`, `depends-on: kratos,seaweedfs` | |
| `collabora` | Deployment `collabora` in `lasuite` | `service: collabora`, `category: platform` | `display-name: "Collabora (Office)"`, `kv-path: collabora` | |
### Messaging
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `messages` | Deployments `messages-backend`, `messages-mta-in`, `messages-mta-out` in `lasuite` | `service: messages`, `category: messaging` | `display-name: "Messages (Mail)"`, `kv-path: messages`, `db-user: messages`, `db-name: messages_db`, `build-target: messages`, `depends-on: postgres,openbao` | Multi-deploy: all 3 get the same `service` label |
| `tuwunel` | Deployment `tuwunel` in `matrix` | `service: tuwunel`, `category: messaging` | `display-name: "Tuwunel (Matrix)"`, `kv-path: tuwunel`, `build-target: tuwunel`, `depends-on: openbao` | |
### Media (namespace: `media`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `livekit` | Deployment `livekit-server` in `media` | `service: livekit`, `category: media` | `display-name: "LiveKit (WebRTC)"`, `kv-path: livekit`, `depends-on: openbao` | |
### Storage (namespace: `storage`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `seaweedfs` | Deployment `seaweedfs-filer` in `storage` | `service: seaweedfs`, `category: storage` | `display-name: "SeaweedFS (S3)"`, `kv-path: seaweedfs`, `depends-on: openbao` | |
### Monitoring (namespace: `monitoring`)
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `grafana` | Deployment `grafana` in `monitoring` | `service: grafana`, `category: monitoring` | `display-name: "Grafana"`, `kv-path: grafana`, `depends-on: openbao` | |
| `prometheus` | Deployment `prometheus` in `monitoring` | `service: prometheus`, `category: monitoring` | `display-name: "Prometheus"` | No KV, no DB, no deps |
| `loki` | Deployment `loki` in `monitoring` | `service: loki`, `category: monitoring` | `display-name: "Loki"` | No KV, no DB, no deps |
### Infra
| Service | K8s Resource | Labels | Annotations | Notes |
|---|---|---|---|---|
| `cilium` | Deployment `cilium-operator` in `kube-system` | `service: cilium`, `category: infra` | `display-name: "Cilium (CNI)"` | No health check (HealthCheck::None) |
| `longhorn` | ConfigMap `sunbeam-svc-longhorn` in `longhorn-system` | `service: longhorn`, `category: infra`, `virtual: "true"` | `display-name: "Longhorn (Storage)"` | Virtual: no deployments listed |
| `cert-manager` | Deployment `cert-manager` in `cert-manager` | `service: cert-manager`, `category: infra` | `display-name: "cert-manager (TLS)"` | No health check |
| `ingress` | Deployment `pingora` in `ingress` | `service: ingress`, `category: infra` | `display-name: "Ingress (Proxy)"`, `depends-on: cert-manager` | No health check |
| `vso` | Deployment `vault-secrets-operator` in `vault-secrets-operator` | `service: vso`, `category: infra` | `display-name: "Vault Secrets Operator"`, `depends-on: openbao` | No health check |
| `headscale` | Deployment `headscale` in `vpn` | `service: headscale`, `category: infra` | `display-name: "Headscale (VPN)"`, `db-user: headscale`, `db-name: headscale_db`, `depends-on: postgres` | No health check, no KV, but has a DB |
| `scaleway-s3` | ConfigMap `sunbeam-svc-scaleway-s3` in `external` | `service: scaleway-s3`, `category: infra`, `virtual: "true"` | `display-name: "Scaleway S3"`, `kv-path: scaleway-s3` | Virtual: external service, no pods |
---
## 3. Example Patches
### Example 1: Standard Deployment (hydra)
```yaml
# Deployment in namespace: ory
apiVersion: apps/v1
kind: Deployment
metadata:
name: hydra
namespace: ory
labels:
sunbeam.pt/service: hydra
sunbeam.pt/category: auth
annotations:
sunbeam.pt/display-name: "Hydra (OAuth2/OIDC)"
sunbeam.pt/kv-path: hydra
sunbeam.pt/db-user: hydra
sunbeam.pt/db-name: hydra_db
sunbeam.pt/depends-on: postgres,openbao
```
### Example 2: StatefulSet (openbao)
```yaml
# StatefulSet in namespace: data
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: openbao
namespace: data
labels:
sunbeam.pt/service: openbao
sunbeam.pt/category: data
annotations:
sunbeam.pt/display-name: "OpenBao (Secrets)"
sunbeam.pt/health-check: seal-status
```
### Example 3: CNPG Cluster (postgres)
```yaml
# CNPG Cluster in namespace: data
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres
namespace: data
labels:
sunbeam.pt/service: postgres
sunbeam.pt/category: data
annotations:
sunbeam.pt/display-name: "PostgreSQL (CNPG)"
sunbeam.pt/health-check: cnpg
```
### Example 4: External service ConfigMap (scaleway-s3)
```yaml
# No pods exist for this service; use a ConfigMap placeholder
apiVersion: v1
kind: ConfigMap
metadata:
name: sunbeam-svc-scaleway-s3
namespace: external
labels:
sunbeam.pt/service: scaleway-s3
sunbeam.pt/category: infra
sunbeam.pt/virtual: "true"
annotations:
sunbeam.pt/display-name: "Scaleway S3"
sunbeam.pt/kv-path: scaleway-s3
data: {}
```
### Example 5: Multi-deployment service (messages)
All three Deployments carry the same `sunbeam.pt/service: messages` label. Full annotations go on the primary Deployment; the others only need the labels.
```yaml
# Primary Deployment - carries all annotations
apiVersion: apps/v1
kind: Deployment
metadata:
name: messages-backend
namespace: lasuite
labels:
sunbeam.pt/service: messages
sunbeam.pt/category: messaging
annotations:
sunbeam.pt/display-name: "Messages (Mail)"
sunbeam.pt/kv-path: messages
sunbeam.pt/db-user: messages
sunbeam.pt/db-name: messages_db
sunbeam.pt/build-target: messages
sunbeam.pt/depends-on: postgres,openbao
---
# Secondary Deployment - labels only
apiVersion: apps/v1
kind: Deployment
metadata:
name: messages-mta-in
namespace: lasuite
labels:
sunbeam.pt/service: messages
sunbeam.pt/category: messaging
---
# Secondary Deployment - labels only
apiVersion: apps/v1
kind: Deployment
metadata:
name: messages-mta-out
namespace: lasuite
labels:
sunbeam.pt/service: messages
sunbeam.pt/category: messaging
```
The same pattern applies to `people-celery` (Deployments: `people-celery-worker`, `people-celery-beat`).
---
## 4. Verification
### List all sunbeam-managed services
```bash
kubectl get deploy,sts,cm -A -l sunbeam.pt/service
```
### Check a specific service
```bash
kubectl get deploy -n ory -l sunbeam.pt/service=hydra \
-o jsonpath='{.items[0].metadata.annotations}'
```
### List all services in a category
```bash
kubectl get deploy,sts,cm -A -l sunbeam.pt/category=platform
```
### List virtual services only
```bash
kubectl get cm -A -l sunbeam.pt/virtual=true
```
### Verify all 33 services are discoverable
```bash
kubectl get deploy,sts,cm -A -l sunbeam.pt/service \
-o jsonpath='{range .items[*]}{.metadata.labels.sunbeam\.pt/service}{"\n"}{end}' \
| sort -u | wc -l
# Expected: 33
```
### Test with the CLI after labeling
```bash
sunbeam status # Should list all services
sunbeam logs hydra # Should find hydra pods via label selector
sunbeam restart auth # Should restart all services in the auth category
```
---
## Notes
- The `sunbeam.pt/health-check` annotation defaults to `pod-ready` when omitted. Only set it explicitly for `cnpg`, `seal-status`, or custom HTTP paths.
- Services with `HealthCheck::None` in the registry (all Infra services) should **not** have a `health-check` annotation. The CLI treats missing health-check on infra services as "no active health monitoring."
- The `sunbeam.pt/virtual` label is only needed on ConfigMap placeholders for services with no workload resources. The two virtual services are `longhorn` and `scaleway-s3`.
- Namespace is not encoded as a label/annotation because it is intrinsic to the Kubernetes resource itself.