Do's and don'ts, kustomize patterns, secret management, deployment conventions, naming conventions, AI config, domain patterns.
5.9 KiB
House Rules, Darling 🏠
These are the conventions for working in The Super Boujee Business Box ✨ infrastructure. Follow them and everything stays clean. Ignore them and things get messy. We don't do messy.
The Don'ts ❌
| Rule | Why |
|---|---|
| No Helm charts for simple resources | Plain YAML when a Deployment + Service + ConfigMap is all you need |
| No Ingress resources | Everything routes through Pingora — add a route in the proxy config |
| No Terraform / Pulumi | Kustomize + sunbeam CLI. That's the stack. |
| No RBAC / NetworkPolicy / PodSecurityPolicy | Linkerd handles mTLS. Keep it simple. |
| No new namespaces without discussion | The namespace layout is intentional |
| No hardcoded domains | Use DOMAIN_SUFFIX placeholder — gets replaced at deploy time |
| No TLS keys in Git | Secrets live in OpenBao, synced by Vault Secrets Operator |
| No configMapGenerator / secretGenerator | Plain YAML ConfigMaps and Secrets |
| No commonLabels / commonAnnotations | They cause merge conflicts and confusion |
| No abstract base layers or nested overlays | One level: base → overlay. That's it. |
The Do's ✅
Kustomize Patterns
Base holds canonical config. Everything goes in base/{namespace}/:
base/{namespace}/
├── namespace.yaml
├── kustomization.yaml
├── {app}-deployment.yaml
├── {app}-service.yaml
├── {app}-config.yaml
├── {chart}-values.yaml # Helm chart values
├── vault-secrets.yaml # VaultStaticSecret + VaultDynamicSecret
├── patch-{what}.yaml # Strategic merge patches
├── {component}-alertrules.yaml # PrometheusRule resources
└── {component}-servicemonitor.yaml
Overlays hold only patches. Environment-specific overrides in overlays/{env}/:
overlays/{env}/
├── kustomization.yaml
├── patch-*.yaml # Resource limits, env-specific config
└── values-*.yaml # Helm value overrides
ConfigMaps & Secrets
- ConfigMaps: Use
envFromto inject all keys as env vars - Secrets: Use individual
enventries withsecretKeyRef(explicit about what's secret) - Shared ConfigMaps in lasuite namespace:
lasuite-postgres,lasuite-valkey,lasuite-s3,lasuite-oidc-provider,lasuite-resource-server
Secret Management
Every secret follows the Vault pattern:
# Static secret (OIDC keys, Django secrets, DKIM keys)
VaultStaticSecret:
mount: secret
type: kv-v2
refreshAfter: 30s
# Dynamic secret (database credentials)
VaultDynamicSecret:
mount: database
path: static-creds/{app}
refreshAfter: 5m
rolloutRestartTargets:
- kind: Deployment
name: {app}
Dynamic secrets rotate every 5 minutes. The Vault Secrets Operator handles the K8s Secret lifecycle.
Deployments
- Init containers run migrations:
python manage.py migrate - Short image names — the registry is set via
images:in the overlay kustomization - Liveness probes:
/__heartbeat__ - Readiness probes:
/__lbheartbeat__ - Resource limits on every pod — no unbounded memory
- Linkerd injection:
linkerd.io/inject: enabledannotation on all application namespaces
OIDC Clients
Declare as HydraOAuth2Client CRD. Hydra Maester creates the K8s Secret:
apiVersion: hydra.ory.sh/v1alpha1
kind: OAuth2Client
metadata:
name: oidc-{app}
namespace: lasuite
spec:
grantTypes: [authorization_code, refresh_token]
responseTypes: [code]
scope: openid email profile
redirectUris:
- https://{app}.DOMAIN_SUFFIX/api/v1.0/callback/
secretName: oidc-{app}
Helm Charts
Used for complex components where plain YAML isn't practical:
| Chart | Component |
|---|---|
| CloudNativePG | PostgreSQL operator |
| Ory Kratos | Identity management |
| Ory Hydra | OAuth2/OIDC |
| Gitea | Git hosting |
| kube-prometheus-stack | Monitoring |
| Loki | Log aggregation |
| Tempo | Tracing |
| Alloy | Collection agent |
| LiveKit | Video conferencing |
| OpenBao | Secrets management |
| cert-manager | TLS certificates |
| Longhorn | Volume management |
| Drive | File management |
| Docs | Document editing |
Values go in {chart}-values.yaml in the base directory. Overlay-specific overrides in values-{chart}.yaml.
Naming Conventions
| Thing | Pattern | Example |
|---|---|---|
| Deployments | {app}-deployment.yaml |
sol-deployment.yaml |
| Services | {app}-service.yaml |
sol-service.yaml |
| ConfigMaps | {app}-config.yaml |
sol-config.yaml |
| Secrets | From Vault: {app}-{purpose} |
messages-django-secret |
| OIDC clients | oidc-{app} |
oidc-drive |
| Alert rules | {component}-alertrules.yaml |
postgres-alertrules.yaml |
| ServiceMonitors | {component}-servicemonitor.yaml |
gitea-servicemonitor.yaml |
| Dashboards | dashboards-{domain}.yaml |
dashboards-ingress.yaml |
| Helm values | {chart}-values.yaml |
drive-values.yaml |
| Patches | patch-{what}.yaml |
patch-drive-wopi-init.yaml |
| S3 buckets | sunbeam-{purpose} |
sunbeam-game-assets |
AI Configuration
Three env vars, consistent across all components:
AI_BASE_URL=https://api.scaleway.ai/v1/
AI_API_KEY=<SCW_SECRET_KEY>
AI_MODEL=mistral-small-3.2-24b-instruct-2506
Scaleway Generative APIs — hosted in Paris, GDPR-compliant, OpenAI-compatible. ~€1-5/month for a three-person studio.
Domain Pattern
All apps follow {prefix}.DOMAIN_SUFFIX:
docs, meet, drive, mail, messages, people, find, src, auth,
integration, cal, projects, s3, livekit, metrics, systemmetrics,
systemlogs, systemtracing, vault, search, id, hydra
DOMAIN_SUFFIX is replaced at deploy time:
- Production:
sunbeam.pt - Local:
{LIMA_IP}.sslip.io
The Golden Rule
If you can derive it from the code, don't store it separately. If it needs to be secret, put it in OpenBao. If it's environment-specific, put it in the overlay. Everything else goes in base. Keep it flat, keep it obvious, keep it boujee. 💅