docs: service discovery labels migration guide
313-line walkthrough for adopting the `sunbeam.pt/*` label scheme on existing manifests in sbbb. Documents the required labels, optional annotations, virtual-service ConfigMap pattern, and the multi-deployment grouping convention. Includes a complete table of the 33 services with their target K8s resources and the values to put on each. Teams onboarding new services can follow this without having to read the registry source.
This commit is contained in:
313
docs/service-discovery-labels.md
Normal file
313
docs/service-discovery-labels.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user