Skip to content

Platform-Three (`.p3/`) Structure

FieldValue
TypeAgent Reference
Source~/.copilot/agents/_refs/platform-sre-kubernetes/p3-structure.md
DescriptionNot 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 ApplicationSet
docs/
/secrets/
1password-requirements.md # human-readable secret contract

Chart standards

  • Chart.yamlappVersion matches the released image tag/digest. version is 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.yaml looks like a copy of values.yaml, you’re doing it wrong.
  • _helpers.tpl — every template uses include "<chart>.fullname", .labels, .selectorLabels. No hand-rolled label maps.

Image and release controls

  • Never :latest in any environment. Production prefers digest pinning (@sha256:…).
  • Image tag flows: CI builds & signs (cosign) → pushes to Harbor/GHCR → updates values.<env>.yaml via PR → ArgoCD syncs.
  • Chart.yaml.appVersion and the values-file image tag must agree at release time.

Resource, health, HA defaults (every Deployment must set)

  • resources.requests and resources.limits for CPU and memory — no exceptions.
  • livenessProbe, readinessProbe, and startupProbe (for slow-boot apps).
  • replicas: >= 2 in staging/prod; 1 acceptable in test.
  • PodDisruptionBudget with minAvailable: 1 (or maxUnavailable: 25% for larger fleets).
  • topologySpreadConstraints across zones, or podAntiAffinity at minimum.
  • HorizontalPodAutoscaler whenever load is variable; pin min replicas at the PDB floor.
  • RollingUpdate strategy: maxSurge: 25%, maxUnavailable: 0 for zero-downtime.

Service & ingress

  • Service is ClusterIP; only kube-proxy-internal traffic.
  • IngressRoute (Traefik CRD) over plain Ingress when available — typed middleware, native TLS, redirects.
  • TLS via cert-manager Certificate resources, never hand-managed secrets.

Observability hooks

  • ServiceMonitor always 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/v1alpha1
kind: Application
metadata:
name: <service>-<env>
namespace: argocd
spec:
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.