Platform-Three (`.p3/`) Structure
| Field | Value |
|---|---|
| Type | Agent Reference |
| Source | ~/.copilot/agents/_refs/platform-sre-kubernetes/p3-structure.md |
| Description | Not specified |
Source Content
Platform-Three (.p3/) Structure
Every service in the P3 ecosystem deploys from the same chart layout. New services start by copying this skeleton, then editing values — never templates.
Directory layout
/.p3/ /helm/ Chart.yaml values.yaml # base values, all envs inherit /values/ values.test.yaml # ephemeral CI/preview values.staging.yaml values.prod.yaml /templates/ _helpers.tpl # name, labels, selector helpers deployment.yaml service.yaml ingress.yaml # IngressRoute (Traefik) preferred servicemonitor.yaml # Prometheus scrape networkpolicy.yaml # least-privilege ingress/egress poddisruptionbudget.yaml hpa.yaml /database/ cluster.yaml # CloudNativePG Cluster pooler.yaml # CloudNativePG Pooler (pgbouncer) /secrets/ onepassword-item.yaml # 1Password OnePasswordItem CR /argocd/ application.yaml # ArgoCD Application or ApplicationSetdocs/ /secrets/ 1password-requirements.md # human-readable secret contractChart standards
Chart.yaml—appVersionmatches the released image tag/digest.versionis bumped on chart change.values.yaml— sane defaults for production. Lower envs override, not the other way round (no “if env=prod” branches in templates).- Env values — only the deltas. If
values.staging.yamllooks like a copy ofvalues.yaml, you’re doing it wrong. _helpers.tpl— every template usesinclude "<chart>.fullname",.labels,.selectorLabels. No hand-rolled label maps.
Image and release controls
- Never
:latestin any environment. Production prefers digest pinning (@sha256:…). - Image tag flows: CI builds & signs (cosign) → pushes to Harbor/GHCR → updates
values.<env>.yamlvia PR → ArgoCD syncs. Chart.yaml.appVersionand the values-file image tag must agree at release time.
Resource, health, HA defaults (every Deployment must set)
resources.requestsandresources.limitsfor CPU and memory — no exceptions.livenessProbe,readinessProbe, andstartupProbe(for slow-boot apps).replicas: >= 2in staging/prod; 1 acceptable intest.PodDisruptionBudgetwithminAvailable: 1(ormaxUnavailable: 25%for larger fleets).topologySpreadConstraintsacross zones, orpodAntiAffinityat minimum.HorizontalPodAutoscalerwhenever load is variable; pin min replicas at the PDB floor.RollingUpdatestrategy:maxSurge: 25%,maxUnavailable: 0for zero-downtime.
Service & ingress
ServiceisClusterIP; onlykube-proxy-internal traffic.IngressRoute(Traefik CRD) over plainIngresswhen available — typed middleware, native TLS, redirects.- TLS via
cert-managerCertificateresources, never hand-managed secrets.
Observability hooks
ServiceMonitoralways present, scraping/metrics.- Annotate the Deployment with the dashboard UID (
grafana.com/dashboard-uid: <uid>) so the on-call runbook can deep-link. - Logs flow via stdout → Promtail/Vector → Loki. No sidecar log shippers.
ArgoCD application
apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: <service>-<env> namespace: argocdspec: project: platform-three source: repoURL: https://github.com/<org>/<repo> path: .p3/helm targetRevision: main helm: valueFiles: - values.yaml - values/values.<env>.yaml destination: server: https://kubernetes.default.svc namespace: <service> syncPolicy: automated: { prune: true, selfHeal: true } syncOptions: [CreateNamespace=true, ServerSideApply=true]prod typically uses automated: false with a manual sync gate, or a separate Application whose targetRevision is a tag/SHA bumped by a release PR.